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

Compare changes

Choose any two refs to compare.

+69
cmd/ugitd/args.cue
···
··· 1 + import "strings" 2 + 3 + // Schema 4 + #Port: int & >0 & <65536 5 + #Link: string & strings.Contains(",") 6 + 7 + #Config: { 8 + "repo-dir": string 9 + "show-private": bool 10 + ssh: { 11 + enable: bool 12 + "authorized-keys": string 13 + "clone-url": string 14 + port: #Port 15 + "host-key": string 16 + } 17 + http: { 18 + enable: bool 19 + "clone-url": string 20 + port: #Port 21 + } 22 + meta: { 23 + title: string 24 + description: string 25 + } 26 + profile?: { 27 + username?: string 28 + email?: string 29 + links?: [...#Link] 30 + } 31 + log: { 32 + json: bool 33 + level: "debug" | "info" | "warn" | "warning" | "error" 34 + } 35 + 36 + // Constraints 37 + if ssh.port == http.port { 38 + error("ssh.port and http.port cannot be the same") 39 + } 40 + } 41 + 42 + // Defaults 43 + #Config: { 44 + "repo-dir": ".ugit" 45 + "show-private": false 46 + ssh: { 47 + enable: true 48 + "authorized-keys": ".ssh/authorized_keys" 49 + "clone-url": "ssh://localhost:8448" 50 + port: 8448 51 + "host-key": ".ssh/ugit_ed25519" 52 + } 53 + http: { 54 + enable: true 55 + "clone-url": "http://localhost:8449" 56 + port: 8449 57 + } 58 + meta: { 59 + title: "uGit" 60 + description: "Minimal git server" 61 + } 62 + log: { 63 + json: false 64 + level: "info" 65 + } 66 + } 67 + 68 + // Apply schema 69 + #Config
+10 -5
cmd/ugitd/args.go
··· 1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 "log/slog" 7 "strings" 8 9 "github.com/peterbourgon/ff/v3" 10 - "github.com/peterbourgon/ff/v3/ffyaml" 11 ) 12 13 type cliArgs struct { 14 RepoDir string 15 SSH sshArgs ··· 18 Profile profileArgs 19 Log logArgs 20 ShowPrivate bool 21 - TUI bool 22 } 23 24 type sshArgs struct { ··· 58 59 func parseArgs(args []string) (c cliArgs, e error) { 60 fs := flag.NewFlagSet("ugitd", flag.ContinueOnError) 61 - fs.String("config", "ugit.yaml", "Path to config file") 62 63 c = cliArgs{ 64 RepoDir: ".ugit", ··· 115 fs.StringVar(&c.Meta.Description, "meta.description", c.Meta.Description, "App description") 116 fs.StringVar(&c.Profile.Username, "profile.username", c.Profile.Username, "Username for index page") 117 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 fs.Func("profile.links", "Link(s) for index page", func(s string) error { 120 parts := strings.SplitN(s, ",", 2) 121 if len(parts) != 2 { ··· 128 return nil 129 }) 130 131 return c, ff.Parse(fs, args, 132 ff.WithEnvVarPrefix("UGIT"), 133 ff.WithConfigFileFlag("config"), 134 ff.WithAllowMissingConfigFile(true), 135 - ff.WithConfigFileParser(ffyaml.Parser), 136 ) 137 }
··· 1 package main 2 3 import ( 4 + _ "embed" 5 "flag" 6 "fmt" 7 "log/slog" 8 "strings" 9 10 "github.com/peterbourgon/ff/v3" 11 + "go.jolheiser.com/ffcue" 12 ) 13 14 + //go:embed args.cue 15 + var schema string 16 + 17 type cliArgs struct { 18 RepoDir string 19 SSH sshArgs ··· 22 Profile profileArgs 23 Log logArgs 24 ShowPrivate bool 25 } 26 27 type sshArgs struct { ··· 61 62 func parseArgs(args []string) (c cliArgs, e error) { 63 fs := flag.NewFlagSet("ugitd", flag.ContinueOnError) 64 + fs.String("config", "ugit.cue", "Path to config file") 65 66 c = cliArgs{ 67 RepoDir: ".ugit", ··· 118 fs.StringVar(&c.Meta.Description, "meta.description", c.Meta.Description, "App description") 119 fs.StringVar(&c.Profile.Username, "profile.username", c.Profile.Username, "Username for index page") 120 fs.StringVar(&c.Profile.Email, "profile.email", c.Profile.Email, "Email for index page") 121 fs.Func("profile.links", "Link(s) for index page", func(s string) error { 122 parts := strings.SplitN(s, ",", 2) 123 if len(parts) != 2 { ··· 130 return nil 131 }) 132 133 + parser := &ffcue.ParseConfig{ 134 + Constraints: schema, 135 + } 136 return c, ff.Parse(fs, args, 137 ff.WithEnvVarPrefix("UGIT"), 138 ff.WithConfigFileFlag("config"), 139 ff.WithAllowMissingConfigFile(true), 140 + ff.WithConfigFileParser(parser.Parse), 141 ) 142 }
-9
cmd/ugitd/main.go
··· 20 "go.jolheiser.com/ugit/internal/git" 21 "go.jolheiser.com/ugit/internal/http" 22 "go.jolheiser.com/ugit/internal/ssh" 23 - "go.jolheiser.com/ugit/internal/tui" 24 ) 25 26 func main() { ··· 39 args.RepoDir, err = filepath.Abs(args.RepoDir) 40 if err != nil { 41 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 } 51 52 slog.SetLogLoggerLevel(args.Log.Level)
··· 20 "go.jolheiser.com/ugit/internal/git" 21 "go.jolheiser.com/ugit/internal/http" 22 "go.jolheiser.com/ugit/internal/ssh" 23 ) 24 25 func main() { ··· 38 args.RepoDir, err = filepath.Abs(args.RepoDir) 39 if err != nil { 40 panic(err) 41 } 42 43 slog.SetLogLoggerLevel(args.Log.Level)
+2
config.cue
···
··· 1 + http: port: 1 2 + ssh: port: 1
+3 -3
flake.lock
··· 2 "nodes": { 3 "nixpkgs": { 4 "locked": { 5 - "lastModified": 1736241350, 6 - "narHash": "sha256-CHd7yhaDigUuJyDeX0SADbTM9FXfiWaeNyY34FL1wQU=", 7 "owner": "nixos", 8 "repo": "nixpkgs", 9 - "rev": "8c9fd3e564728e90829ee7dbac6edc972971cd0f", 10 "type": "github" 11 }, 12 "original": {
··· 2 "nodes": { 3 "nixpkgs": { 4 "locked": { 5 + "lastModified": 1755205935, 6 + "narHash": "sha256-EQ6qHuJWguaoBZyxdqsgJqyEdS77k+2CnlKrfFxlkRY=", 7 "owner": "nixos", 8 "repo": "nixpkgs", 9 + "rev": "c5e2e42c112de623adfd662b3e51f0805bf9ff83", 10 "type": "github" 11 }, 12 "original": {
+2 -2
flake.nix
··· 47 gopls 48 air 49 tctp.${system} 50 - tctpl.${system} 51 - vscode-langservers-extracted 52 ]; 53 }; 54 }
··· 47 gopls 48 air 49 tctp.${system} 50 + #tctpl.${system} 51 + #vscode-langservers-extracted 52 ]; 53 }; 54 }
+32 -21
go.mod
··· 5 toolchain go1.23.3 6 7 require ( 8 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 15 github.com/dustin/go-humanize v1.0.1 ··· 18 github.com/go-git/go-billy/v5 v5.6.1 19 github.com/go-git/go-git/v5 v5.13.1 20 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 23 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 26 ) 27 28 require ( 29 dario.cat/mergo v1.0.1 // indirect 30 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 33 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect 34 - github.com/atotto/clipboard v0.1.4 // indirect 35 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 44 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 47 github.com/creack/pty v1.1.24 // indirect 48 github.com/cyphar/filepath-securejoin v0.3.6 // indirect 49 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 50 github.com/dlclark/regexp2 v1.11.4 // indirect 51 github.com/emirpasic/gods v1.18.1 // indirect 52 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect 53 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect 54 github.com/go-logfmt/logfmt v0.6.0 // indirect 55 github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect 56 github.com/hexops/gotextdiff v1.0.3 // indirect 57 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 60 github.com/mattn/go-isatty v0.0.20 // indirect 61 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 64 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect 65 github.com/muesli/cancelreader v0.2.2 // indirect 66 - github.com/muesli/termenv v0.16.0 // indirect 67 github.com/pjbgf/sha1cd v0.3.1 // indirect 68 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 69 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 73 github.com/xanzy/ssh-agent v0.3.3 // indirect 74 - 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 82 gopkg.in/warnings.v0 v0.1.2 // indirect 83 - gopkg.in/yaml.v2 v2.4.0 // indirect 84 )
··· 5 toolchain go1.23.3 6 7 require ( 8 + github.com/a-h/templ v0.3.924 9 github.com/alecthomas/assert/v2 v2.11.0 10 github.com/alecthomas/chroma/v2 v2.15.0 11 github.com/charmbracelet/ssh v0.0.0-20241211182756-4fe22b0f1b7c 12 github.com/charmbracelet/wish v1.4.4 13 github.com/dustin/go-humanize v1.0.1 ··· 16 github.com/go-git/go-billy/v5 v5.6.1 17 github.com/go-git/go-git/v5 v5.13.1 18 github.com/peterbourgon/ff/v3 v3.4.0 19 + github.com/yuin/goldmark v1.7.12 20 github.com/yuin/goldmark-emoji v1.0.4 21 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc 22 + go.jolheiser.com/ffcue v0.0.0-20250816031459-3e3e4f232e75 23 + golang.org/x/net v0.42.0 24 ) 25 26 require ( 27 + cuelang.org/go v0.14.1 // indirect 28 dario.cat/mergo v1.0.1 // indirect 29 github.com/Microsoft/go-winio v0.6.2 // indirect 30 github.com/ProtonMail/go-crypto v1.1.4 // indirect 31 + github.com/a-h/parse v0.0.0-20250122154542-74294addb73e // indirect 32 github.com/alecthomas/repr v0.4.0 // indirect 33 + github.com/andybalholm/brotli v1.1.0 // indirect 34 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect 35 github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect 36 + github.com/cenkalti/backoff/v4 v4.3.0 // indirect 37 + github.com/charmbracelet/bubbletea v1.2.4 // indirect 38 github.com/charmbracelet/keygen v0.5.1 // indirect 39 + github.com/charmbracelet/lipgloss v1.0.0 // indirect 40 github.com/charmbracelet/log v0.4.0 // indirect 41 + github.com/charmbracelet/x/ansi v0.6.0 // indirect 42 github.com/charmbracelet/x/conpty v0.1.0 // indirect 43 github.com/charmbracelet/x/errors v0.0.0-20250107110353-48b574af22a5 // indirect 44 github.com/charmbracelet/x/term v0.2.1 // indirect 45 github.com/charmbracelet/x/termios v0.1.0 // indirect 46 + github.com/cli/browser v1.3.0 // indirect 47 github.com/cloudflare/circl v1.5.0 // indirect 48 + github.com/cockroachdb/apd/v3 v3.2.1 // indirect 49 github.com/creack/pty v1.1.24 // indirect 50 github.com/cyphar/filepath-securejoin v0.3.6 // indirect 51 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 52 github.com/dlclark/regexp2 v1.11.4 // indirect 53 + github.com/emicklei/proto v1.14.2 // indirect 54 github.com/emirpasic/gods v1.18.1 // indirect 55 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect 56 + github.com/fatih/color v1.16.0 // indirect 57 + github.com/fsnotify/fsnotify v1.7.0 // indirect 58 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect 59 github.com/go-logfmt/logfmt v0.6.0 // indirect 60 github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect 61 + github.com/google/uuid v1.6.0 // indirect 62 github.com/hexops/gotextdiff v1.0.3 // indirect 63 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect 64 github.com/kevinburke/ssh_config v1.2.0 // indirect 65 github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 66 + github.com/mattn/go-colorable v0.1.13 // indirect 67 github.com/mattn/go-isatty v0.0.20 // indirect 68 github.com/mattn/go-localereader v0.0.1 // indirect 69 github.com/mattn/go-runewidth v0.0.16 // indirect 70 + github.com/mitchellh/go-wordwrap v1.0.1 // indirect 71 github.com/mmcloughlin/avo v0.6.0 // indirect 72 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect 73 github.com/muesli/cancelreader v0.2.2 // indirect 74 + github.com/muesli/termenv v0.15.3-0.20240509142007-81b8f94111d5 // indirect 75 + github.com/natefinch/atomic v1.0.1 // indirect 76 + github.com/pelletier/go-toml/v2 v2.2.4 // indirect 77 github.com/pjbgf/sha1cd v0.3.1 // indirect 78 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 79 + github.com/protocolbuffers/txtpbfmt v0.0.0-20250627152318-f293424e46b5 // indirect 80 github.com/rivo/uniseg v0.4.7 // indirect 81 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect 82 github.com/skeema/knownhosts v1.3.0 // indirect 83 github.com/xanzy/ssh-agent v0.3.3 // indirect 84 + golang.org/x/crypto v0.40.0 // indirect 85 golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect 86 + golang.org/x/mod v0.26.0 // indirect 87 + golang.org/x/sync v0.16.0 // indirect 88 + golang.org/x/sys v0.34.0 // indirect 89 + golang.org/x/text v0.27.0 // indirect 90 + golang.org/x/tools v0.35.0 // indirect 91 gopkg.in/warnings.v0 v0.1.2 // indirect 92 + gopkg.in/yaml.v3 v3.0.1 // indirect 93 ) 94 + 95 + tool github.com/a-h/templ/cmd/templ
+1 -1
go.mod.sri
··· 1 - sha256-L87PnM43gHrDcsRr3wnkB4e1Th2S0LsSwkXuebAFH44=
··· 1 + sha256-DjweXB8uqEpOIBwGabLCnVL4ZOKkPcJDf6JlAS5FmKI=
+78 -51
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= 3 github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= ··· 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= 8 github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= 9 github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= 10 github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= ··· 13 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= 16 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= 17 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= 18 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= 19 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 github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= 23 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= 34 - github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= 35 - 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= 54 github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= 55 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= 60 github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= 61 github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= 62 github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= ··· 73 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= 76 github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= 77 github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= 78 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= 79 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= 80 github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= 81 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= ··· 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= 96 github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= 97 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= 100 github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= 101 github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= 102 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= ··· 112 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= 117 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 118 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 119 github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= 120 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= 125 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= 126 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= 127 github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= 128 github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= 129 - github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= 130 - github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= 131 github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= 132 github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= 133 github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= 134 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= ··· 139 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 140 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 141 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 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 144 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= 151 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= ··· 159 github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 160 github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= 161 github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= 162 - github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= 163 - github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= 164 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= 170 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= 171 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= 172 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= 179 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= 184 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 185 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 186 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= ··· 188 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 189 golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 190 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 191 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= 194 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= 197 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= 200 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= 203 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 204 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 205 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= ··· 207 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= 208 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 209 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 210 - gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 211 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 212 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 213 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 214 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=
··· 1 + cuelabs.dev/go/oci/ociregistry v0.0.0-20250715075730-49cab49c8e9d h1:lX0EawyoAu4kgMJJfy7MmNkIHioBcdBGFRSKDZ+CWo0= 2 + cuelabs.dev/go/oci/ociregistry v0.0.0-20250715075730-49cab49c8e9d/go.mod h1:4WWeZNxUO1vRoZWAHIG0KZOd6dA25ypyWuwD3ti0Tdc= 3 + cuelang.org/go v0.14.1 h1:kxFAHr7bvrCikbtVps2chPIARazVdnRmlz65dAzKyWg= 4 + cuelang.org/go v0.14.1/go.mod h1:aSP9UZUM5m2izHAHUvqtq0wTlWn5oLjuv2iBMQZBLLs= 5 dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= 6 dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= 7 github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= ··· 9 github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= 10 github.com/ProtonMail/go-crypto v1.1.4 h1:G5U5asvD5N/6/36oIw3k2bOfBn5XVcZrb7PBjzzKKoE= 11 github.com/ProtonMail/go-crypto v1.1.4/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= 12 + github.com/a-h/parse v0.0.0-20250122154542-74294addb73e h1:HjVbSQHy+dnlS6C3XajZ69NYAb5jbGNfHanvm1+iYlo= 13 + github.com/a-h/parse v0.0.0-20250122154542-74294addb73e/go.mod h1:3mnrkvGpurZ4ZrTDbYU84xhwXW2TjTKShSwjRi2ihfQ= 14 + github.com/a-h/templ v0.3.924 h1:t5gZqTneXqvehpNZsgtnlOscnBboNh9aASBH2MgV/0k= 15 + github.com/a-h/templ v0.3.924/go.mod h1:FFAu4dI//ESmEN7PQkJ7E7QfnSEMdcnu7QrAY8Dn334= 16 github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= 17 github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= 18 github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= ··· 21 github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= 22 github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= 23 github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= 24 + github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= 25 + github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= 26 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= 27 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= 28 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= 29 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= 30 github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= 31 github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= 32 + github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= 33 + github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= 34 + github.com/charmbracelet/bubbletea v1.2.4 h1:KN8aCViA0eps9SCOThb2/XPIlea3ANJLUkv3KnQRNCE= 35 + github.com/charmbracelet/bubbletea v1.2.4/go.mod h1:Qr6fVQw+wX7JkWWkVyXYk/ZUQ92a6XNekLXa3rR18MM= 36 github.com/charmbracelet/keygen v0.5.1 h1:zBkkYPtmKDVTw+cwUyY6ZwGDhRxXkEp0Oxs9sqMLqxI= 37 github.com/charmbracelet/keygen v0.5.1/go.mod h1:zznJVmK/GWB6dAtjluqn2qsttiCBhA5MZSiwb80fcHw= 38 + github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg= 39 + github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo= 40 github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM= 41 github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM= 42 github.com/charmbracelet/ssh v0.0.0-20241211182756-4fe22b0f1b7c h1:treQxMBdI2PaD4eOYfFux8stfCkUxhuUxaqGcxKqVpI= 43 github.com/charmbracelet/ssh v0.0.0-20241211182756-4fe22b0f1b7c/go.mod h1:CY1xbl2z+ZeBmNWItKZyxx0zgDgnhmR57+DTsHOobJ4= 44 github.com/charmbracelet/wish v1.4.4 h1:wtfoAMkf8Db9zi+9Lme2f7XKMxL6BqfgDWbqcTUHLaU= 45 github.com/charmbracelet/wish v1.4.4/go.mod h1:XB8v51UxIFMRlUod9lLaAgOsj/wpe+qW9HjsoYIiNMo= 46 + github.com/charmbracelet/x/ansi v0.6.0 h1:qOznutrb93gx9oMiGf7caF7bqqubh6YIM0SWKyA08pA= 47 + github.com/charmbracelet/x/ansi v0.6.0/go.mod h1:KBUFw1la39nl0dLl10l5ORDAqGXaeurTQmwyyVKse/Q= 48 github.com/charmbracelet/x/conpty v0.1.0 h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U= 49 github.com/charmbracelet/x/conpty v0.1.0/go.mod h1:rMFsDJoDwVmiYM10aD4bH2XiRgwI7NYJtQgl5yskjEQ= 50 github.com/charmbracelet/x/errors v0.0.0-20250107110353-48b574af22a5 h1:Hx72S6S4jAfrrWE3pv9IbudVdUV4htBgkOX800o17Bk= 51 github.com/charmbracelet/x/errors v0.0.0-20250107110353-48b574af22a5/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0= 52 github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= 53 github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= 54 github.com/charmbracelet/x/termios v0.1.0 h1:y4rjAHeFksBAfGbkRDmVinMg7x7DELIGAFbdNvxg97k= 55 github.com/charmbracelet/x/termios v0.1.0/go.mod h1:H/EVv/KRnrYjz+fCYa9bsKdqF3S8ouDK0AZEbG7r+/U= 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/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys= 59 github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= 60 + github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= 61 + github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= 62 github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= 63 github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= 64 github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= ··· 75 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 76 github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ= 77 github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64= 78 + github.com/emicklei/proto v1.14.2 h1:wJPxPy2Xifja9cEMrcA/g08art5+7CGJNFNk35iXC1I= 79 + github.com/emicklei/proto v1.14.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= 80 github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= 81 github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= 82 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= 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= 88 github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= 89 github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= 90 github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0= ··· 101 github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc= 102 github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= 103 github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= 104 + github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= 105 + github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= 106 github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= 107 github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= 108 + github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 109 + github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 110 + github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 111 + github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 112 github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= 113 github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= 114 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= ··· 124 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 125 github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= 126 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 127 + github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= 128 + github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 129 github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= 130 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= 131 + github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 132 + github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 133 + github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 134 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 135 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 136 github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= 137 github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= 138 github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= 139 github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 140 + github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= 141 + github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= 142 github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY= 143 github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8= 144 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= 145 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= 146 github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= 147 github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= 148 + github.com/muesli/termenv v0.15.3-0.20240509142007-81b8f94111d5 h1:NiONcKK0EV5gUZcnCiPMORaZA0eBDc+Fgepl9xl4lZ8= 149 + github.com/muesli/termenv v0.15.3-0.20240509142007-81b8f94111d5/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ= 150 + github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= 151 + github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= 152 github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= 153 github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= 154 + github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= 155 + github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= 156 + github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= 157 + github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= 158 + github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= 159 + github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= 160 github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= 161 github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= 162 github.com/pjbgf/sha1cd v0.3.1 h1:Dh2GYdpJnO84lIw0LJwTFXjcNbasP/bklicSznyAaPI= ··· 166 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 167 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 168 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 169 + github.com/protocolbuffers/txtpbfmt v0.0.0-20250627152318-f293424e46b5 h1:WWs1ZFnGobK5ZXNu+N9If+8PDNVB9xAqrib/stUXsV4= 170 + github.com/protocolbuffers/txtpbfmt v0.0.0-20250627152318-f293424e46b5/go.mod h1:BnHogPTyzYAReeQLZrOxyxzS739DaTNtTvohVdbENmA= 171 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 172 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 173 github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 174 + github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= 175 + github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= 176 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= 177 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= 178 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= ··· 186 github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 187 github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= 188 github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= 189 github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 190 github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= 191 + github.com/yuin/goldmark v1.7.12 h1:YwGP/rrea2/CnCtUHgjuolG/PnMxdQtPMO5PvaE2/nY= 192 + github.com/yuin/goldmark v1.7.12/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= 193 github.com/yuin/goldmark-emoji v1.0.4 h1:vCwMkPZSNefSUnOW2ZKRUjBSD5Ok3W78IXhGxxAEF90= 194 github.com/yuin/goldmark-emoji v1.0.4/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U= 195 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= 196 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= 197 + go.jolheiser.com/ffcue v0.0.0-20250816031459-3e3e4f232e75 h1:hu2LcTy2bvgmfEDuaDCfpWIzWN1pHAKfUkAnpgjZYco= 198 + go.jolheiser.com/ffcue v0.0.0-20250816031459-3e3e4f232e75/go.mod h1:IrDGUkvU3xl27+Seb20ZE/H2dzG95m/xmu0Z/B3crUE= 199 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 200 + golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= 201 + golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= 202 golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= 203 golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= 204 + golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= 205 + golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= 206 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 207 + golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= 208 + golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= 209 + golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= 210 + golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= 211 + golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= 212 + golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 213 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 214 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 215 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= ··· 217 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 218 golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 219 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 220 + golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 221 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 222 + golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= 223 + golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 224 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 225 + golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= 226 + golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= 227 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 228 + golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= 229 + golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= 230 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 231 + golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= 232 + golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= 233 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 234 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 235 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= ··· 237 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= 238 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 239 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 240 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 241 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 242 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 243 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+4 -3
internal/git/meta.go
··· 53 54 // UnmarshalJSON implements [json.Unmarshaler] 55 func (t *TagSet) UnmarshalJSON(b []byte) error { 56 var s []string 57 if err := json.Unmarshal(b, &s); err != nil { 58 return err 59 - } 60 - if *t == nil { 61 - *t = make(TagSet) 62 } 63 for _, ss := range s { 64 t.Add(ss)
··· 53 54 // UnmarshalJSON implements [json.Unmarshaler] 55 func (t *TagSet) UnmarshalJSON(b []byte) error { 56 + if *t == nil { 57 + ts := make(TagSet) 58 + t = &ts 59 + } 60 var s []string 61 if err := json.Unmarshal(b, &s); err != nil { 62 return err 63 } 64 for _, ss := range s { 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
+1
internal/html/generate.go
··· 26 otherCSS string 27 ) 28 29 //go:generate go run generate.go 30 func main() { 31 if err := tailwind(); err != nil {
··· 26 otherCSS string 27 ) 28 29 + //go:generate go tool templ generate 30 //go:generate go run generate.go 31 func main() { 32 if err := tailwind(); err != nil {
-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 - }
···
+52
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 + Description string 15 + } 16 + 17 + templ RepoTree(rtc RepoTreeContext) { 18 + @base(rtc.BaseContext) { 19 + @repoHeaderComponent(rtc.RepoHeaderComponentContext) 20 + @repoBreadcrumbComponent(rtc.RepoBreadcrumbComponentContext) 21 + @repoTreeComponent(rtc.RepoTreeComponentContext) 22 + @readmeComponent(rtc.ReadmeComponentContext) 23 + } 24 + } 25 + 26 + type RepoTreeComponentContext struct { 27 + Repo string 28 + Ref string 29 + Tree []git.FileInfo 30 + Back string 31 + } 32 + 33 + func slashDir(name string, isDir bool) string { 34 + if isDir { 35 + return name + "/" 36 + } 37 + return name 38 + } 39 + 40 + templ repoTreeComponent(rtcc RepoTreeComponentContext) { 41 + <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"> 42 + if rtcc.Back != "" { 43 + <div class="col-span-2"></div> 44 + <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> 45 + } 46 + for _, fi := range rtcc.Tree { 47 + <div class="sm:col-span-1 break-keep">{ fi.Mode }</div> 48 + <div class="sm:col-span-1 text-right">{ fi.Size }</div> 49 + <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> 50 + } 51 + </div> 52 + }
+220
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 + Description string 23 + } 24 + 25 + func RepoTree(rtc RepoTreeContext) templ.Component { 26 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 27 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 28 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 29 + return templ_7745c5c3_CtxErr 30 + } 31 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 32 + if !templ_7745c5c3_IsBuffer { 33 + defer func() { 34 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 35 + if templ_7745c5c3_Err == nil { 36 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 37 + } 38 + }() 39 + } 40 + ctx = templ.InitializeContext(ctx) 41 + templ_7745c5c3_Var1 := templ.GetChildren(ctx) 42 + if templ_7745c5c3_Var1 == nil { 43 + templ_7745c5c3_Var1 = templ.NopComponent 44 + } 45 + ctx = templ.ClearChildren(ctx) 46 + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 47 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 48 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 49 + if !templ_7745c5c3_IsBuffer { 50 + defer func() { 51 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 52 + if templ_7745c5c3_Err == nil { 53 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 54 + } 55 + }() 56 + } 57 + ctx = templ.InitializeContext(ctx) 58 + templ_7745c5c3_Err = repoHeaderComponent(rtc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer) 59 + if templ_7745c5c3_Err != nil { 60 + return templ_7745c5c3_Err 61 + } 62 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ") 63 + if templ_7745c5c3_Err != nil { 64 + return templ_7745c5c3_Err 65 + } 66 + templ_7745c5c3_Err = repoBreadcrumbComponent(rtc.RepoBreadcrumbComponentContext).Render(ctx, templ_7745c5c3_Buffer) 67 + if templ_7745c5c3_Err != nil { 68 + return templ_7745c5c3_Err 69 + } 70 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " ") 71 + if templ_7745c5c3_Err != nil { 72 + return templ_7745c5c3_Err 73 + } 74 + templ_7745c5c3_Err = repoTreeComponent(rtc.RepoTreeComponentContext).Render(ctx, templ_7745c5c3_Buffer) 75 + if templ_7745c5c3_Err != nil { 76 + return templ_7745c5c3_Err 77 + } 78 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " ") 79 + if templ_7745c5c3_Err != nil { 80 + return templ_7745c5c3_Err 81 + } 82 + templ_7745c5c3_Err = readmeComponent(rtc.ReadmeComponentContext).Render(ctx, templ_7745c5c3_Buffer) 83 + if templ_7745c5c3_Err != nil { 84 + return templ_7745c5c3_Err 85 + } 86 + return nil 87 + }) 88 + templ_7745c5c3_Err = base(rtc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 89 + if templ_7745c5c3_Err != nil { 90 + return templ_7745c5c3_Err 91 + } 92 + return nil 93 + }) 94 + } 95 + 96 + type RepoTreeComponentContext struct { 97 + Repo string 98 + Ref string 99 + Tree []git.FileInfo 100 + Back string 101 + } 102 + 103 + func slashDir(name string, isDir bool) string { 104 + if isDir { 105 + return name + "/" 106 + } 107 + return name 108 + } 109 + 110 + func repoTreeComponent(rtcc RepoTreeComponentContext) templ.Component { 111 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 112 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 113 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 114 + return templ_7745c5c3_CtxErr 115 + } 116 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 117 + if !templ_7745c5c3_IsBuffer { 118 + defer func() { 119 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 120 + if templ_7745c5c3_Err == nil { 121 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 122 + } 123 + }() 124 + } 125 + ctx = templ.InitializeContext(ctx) 126 + templ_7745c5c3_Var3 := templ.GetChildren(ctx) 127 + if templ_7745c5c3_Var3 == nil { 128 + templ_7745c5c3_Var3 = templ.NopComponent 129 + } 130 + ctx = templ.ClearChildren(ctx) 131 + 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\">") 132 + if templ_7745c5c3_Err != nil { 133 + return templ_7745c5c3_Err 134 + } 135 + if rtcc.Back != "" { 136 + 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=\"") 137 + if templ_7745c5c3_Err != nil { 138 + return templ_7745c5c3_Err 139 + } 140 + var templ_7745c5c3_Var4 templ.SafeURL 141 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, rtcc.Back))) 142 + if templ_7745c5c3_Err != nil { 143 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 44, Col: 194} 144 + } 145 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 146 + if templ_7745c5c3_Err != nil { 147 + return templ_7745c5c3_Err 148 + } 149 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\">..</a></div>") 150 + if templ_7745c5c3_Err != nil { 151 + return templ_7745c5c3_Err 152 + } 153 + } 154 + for _, fi := range rtcc.Tree { 155 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"sm:col-span-1 break-keep\">") 156 + if templ_7745c5c3_Err != nil { 157 + return templ_7745c5c3_Err 158 + } 159 + var templ_7745c5c3_Var5 string 160 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fi.Mode) 161 + if templ_7745c5c3_Err != nil { 162 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 47, Col: 50} 163 + } 164 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 165 + if templ_7745c5c3_Err != nil { 166 + return templ_7745c5c3_Err 167 + } 168 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div><div class=\"sm:col-span-1 text-right\">") 169 + if templ_7745c5c3_Err != nil { 170 + return templ_7745c5c3_Err 171 + } 172 + var templ_7745c5c3_Var6 string 173 + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fi.Size) 174 + if templ_7745c5c3_Err != nil { 175 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 48, Col: 50} 176 + } 177 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 178 + if templ_7745c5c3_Err != nil { 179 + return templ_7745c5c3_Err 180 + } 181 + 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=\"") 182 + if templ_7745c5c3_Err != nil { 183 + return templ_7745c5c3_Err 184 + } 185 + var templ_7745c5c3_Var7 templ.SafeURL 186 + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, fi.Path))) 187 + if templ_7745c5c3_Err != nil { 188 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 49, Col: 222} 189 + } 190 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 191 + if templ_7745c5c3_Err != nil { 192 + return templ_7745c5c3_Err 193 + } 194 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">") 195 + if templ_7745c5c3_Err != nil { 196 + return templ_7745c5c3_Err 197 + } 198 + var templ_7745c5c3_Var8 string 199 + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(slashDir(fi.Name(), fi.IsDir)) 200 + if templ_7745c5c3_Err != nil { 201 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 49, Col: 256} 202 + } 203 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 204 + if templ_7745c5c3_Err != nil { 205 + return templ_7745c5c3_Err 206 + } 207 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</a></div>") 208 + if templ_7745c5c3_Err != nil { 209 + return templ_7745c5c3_Err 210 + } 211 + } 212 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div>") 213 + if templ_7745c5c3_Err != nil { 214 + return templ_7745c5c3_Err 215 + } 216 + return nil 217 + }) 218 + } 219 + 220 + var _ = templruntime.GeneratedTemplate
+1 -1
internal/html/tailwind.go
··· 5 6 func TailwindHandler(w http.ResponseWriter, r *http.Request) { 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))}}")) 9 }
··· 5 6 func TailwindHandler(w http.ResponseWriter, r *http.Request) { 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}.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 }
+2 -2
internal/http/index.go
··· 60 }) 61 } 62 63 - if err := html.IndexTemplate(html.IndexContext{ 64 BaseContext: rh.baseContext(), 65 Profile: html.IndexProfile{ 66 Username: rh.s.Profile.Username, ··· 68 Links: links, 69 }, 70 Repos: repos, 71 - }).Render(w); err != nil { 72 return httperr.Error(err) 73 } 74
··· 60 }) 61 } 62 63 + if err := html.Index(html.IndexContext{ 64 BaseContext: rh.baseContext(), 65 Profile: html.IndexProfile{ 66 Username: rh.s.Profile.Username, ··· 68 Links: links, 69 }, 70 Repos: repos, 71 + }).Render(r.Context(), w); err != nil { 72 return httperr.Error(err) 73 } 74
+12 -12
internal/http/repo.go
··· 47 if path != "" { 48 back = filepath.Dir(path) 49 } 50 - if err := html.RepoTreeTemplate(html.RepoTreeContext{ 51 Description: repo.Meta.Description, 52 BaseContext: rh.baseContext(), 53 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), ··· 61 ReadmeComponentContext: html.ReadmeComponentContext{ 62 Markdown: readmeContent, 63 }, 64 - }).Render(w); err != nil { 65 return httperr.Error(err) 66 } 67 ··· 100 } 101 } 102 103 - if err := html.RepoFileTemplate(html.RepoFileContext{ 104 BaseContext: rh.baseContext(), 105 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 106 RepoBreadcrumbComponentContext: rh.repoBreadcrumbContext(repo, r, path), 107 Code: buf.String(), 108 Commit: commit, 109 Path: path, 110 - }).Render(w); err != nil { 111 return httperr.Error(err) 112 } 113 ··· 127 return httperr.Error(err) 128 } 129 130 - if err := html.RepoRefsTemplate(html.RepoRefsContext{ 131 BaseContext: rh.baseContext(), 132 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 133 Branches: branches, 134 Tags: tags, 135 - }).Render(w); err != nil { 136 return httperr.Error(err) 137 } 138 ··· 147 return httperr.Error(err) 148 } 149 150 - if err := html.RepoLogTemplate(html.RepoLogContext{ 151 BaseContext: rh.baseContext(), 152 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 153 Commits: commits, 154 - }).Render(w); err != nil { 155 return httperr.Error(err) 156 } 157 ··· 174 commit.Files[idx].Patch = patch.String() 175 } 176 177 - if err := html.RepoCommitTemplate(html.RepoCommitContext{ 178 BaseContext: rh.baseContext(), 179 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 180 Commit: commit, 181 - }).Render(w); err != nil { 182 return httperr.Error(err) 183 } 184 ··· 218 } 219 } 220 221 - if err := html.RepoSearchTemplate(html.SearchContext{ 222 BaseContext: rh.baseContext(), 223 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 224 Results: results, 225 - }).Render(w); err != nil { 226 return httperr.Error(err) 227 } 228
··· 47 if path != "" { 48 back = filepath.Dir(path) 49 } 50 + if err := html.RepoTree(html.RepoTreeContext{ 51 Description: repo.Meta.Description, 52 BaseContext: rh.baseContext(), 53 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), ··· 61 ReadmeComponentContext: html.ReadmeComponentContext{ 62 Markdown: readmeContent, 63 }, 64 + }).Render(r.Context(), w); err != nil { 65 return httperr.Error(err) 66 } 67 ··· 100 } 101 } 102 103 + if err := html.RepoFile(html.RepoFileContext{ 104 BaseContext: rh.baseContext(), 105 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 106 RepoBreadcrumbComponentContext: rh.repoBreadcrumbContext(repo, r, path), 107 Code: buf.String(), 108 Commit: commit, 109 Path: path, 110 + }).Render(r.Context(), w); err != nil { 111 return httperr.Error(err) 112 } 113 ··· 127 return httperr.Error(err) 128 } 129 130 + if err := html.RepoRefs(html.RepoRefsContext{ 131 BaseContext: rh.baseContext(), 132 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 133 Branches: branches, 134 Tags: tags, 135 + }).Render(r.Context(), w); err != nil { 136 return httperr.Error(err) 137 } 138 ··· 147 return httperr.Error(err) 148 } 149 150 + if err := html.RepoLog(html.RepoLogContext{ 151 BaseContext: rh.baseContext(), 152 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 153 Commits: commits, 154 + }).Render(r.Context(), w); err != nil { 155 return httperr.Error(err) 156 } 157 ··· 174 commit.Files[idx].Patch = patch.String() 175 } 176 177 + if err := html.RepoCommit(html.RepoCommitContext{ 178 BaseContext: rh.baseContext(), 179 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 180 Commit: commit, 181 + }).Render(r.Context(), w); err != nil { 182 return httperr.Error(err) 183 } 184 ··· 218 } 219 } 220 221 + if err := html.RepoSearch(html.SearchContext{ 222 BaseContext: rh.baseContext(), 223 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 224 Results: results, 225 + }).Render(r.Context(), w); err != nil { 226 return httperr.Error(err) 227 } 228
+18 -25
internal/ssh/wish.go
··· 12 "text/tabwriter" 13 14 "go.jolheiser.com/ugit/internal/git" 15 - "go.jolheiser.com/ugit/internal/tui" 16 17 "github.com/charmbracelet/ssh" 18 "github.com/charmbracelet/wish" ··· 100 } 101 } 102 103 - // No args, start TUI 104 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) 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 - } 125 } 126 - fmt.Fprintf(tw, "%[1]s\t%[3]s\t%[2]s/%[1]s.git\n", strings.TrimSuffix(de.Name(), ".git"), cloneURL, visibility) 127 } 128 - tw.Flush() 129 } 130 - return 131 } 132 sh(s) 133 } ··· 181 pktLine := fmt.Sprintf("%04x%s\n", len(msg)+5, msg) 182 _, _ = wish.WriteString(s, pktLine) 183 s.Exit(1) // nolint: errcheck 184 - }
··· 12 "text/tabwriter" 13 14 "go.jolheiser.com/ugit/internal/git" 15 16 "github.com/charmbracelet/ssh" 17 "github.com/charmbracelet/wish" ··· 99 } 100 } 101 102 + // Repo list 103 if len(cmd) == 0 { 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 } 113 + repo, err := git.NewRepo(repoDir, de.Name()) 114 + visibility := "โ“" 115 + if err == nil { 116 + visibility = "๐Ÿ”“" 117 + if repo.Meta.Private { 118 + visibility = "๐Ÿ”’" 119 } 120 } 121 + fmt.Fprintf(tw, "%[1]s\t%[3]s\t%[2]s/%[1]s.git\n", strings.TrimSuffix(de.Name(), ".git"), cloneURL, visibility) 122 } 123 + tw.Flush() 124 } 125 sh(s) 126 } ··· 174 pktLine := fmt.Sprintf("%04x%s\n", len(msg)+5, msg) 175 _, _ = wish.WriteString(s, pktLine) 176 s.Exit(1) // nolint: errcheck 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 - }
···