feat(web): configurable site name in the header
5 files changed, +11 −7
- README.md modified +1 −1
- main.go modified +3 −2
- static/style.css modified +1 −1
- templates/layout.html modified +1 −1
- web.go modified +5 −2
README.md modified
| @@ -70,7 +70,7 @@ The `keys` command runs as root and opens the database read only and answers ssh | ||
| 70 | 70 | sudo -u git gitpocket -root /srv/gitpocket invite |
| 71 | 71 | ``` |
| 72 | 72 | |
| 73 | -If you would rather let anyone sign up then `serve -open` skips the invite step entirely. `gitpocket user <name>` creates an account from the command line with the password read from stdin, and `-ssh-user` changes the account name that appears in clone URLs if you did not call yours `git`. | |
| 73 | +If you would rather let anyone sign up then `serve -open` skips the invite step entirely. `gitpocket user <name>` creates an account from the command line with the password read from stdin, and `-ssh-user` changes the account name that appears in clone URLs if you did not call yours `git`. The header shows `-name`, which defaults to gitpocket, while `-host` stays the hostname used in clone URLs and feeds. | |
| 74 | 74 | |
| 75 | 75 | Mail is configured in `smtp.json` under the root directory and is read once at startup. Plain SMTP takes `host`, `port`, `user`, `password`, `from` and `starttls`, but many VPS providers block every outbound submission port, so `api` and `key` post each message as JSON to a Resend compatible HTTPS endpoint instead. |
| 76 | 76 | |
main.go modified
| @@ -17,7 +17,7 @@ func main() { | ||
| 17 | 17 | flag.Usage = func() { |
| 18 | 18 | fmt.Fprintln(os.Stderr, `usage: gitpocket [-root dir] command |
| 19 | 19 | |
| 20 | - serve [-listen addr] [-host name] [-open] [-ssh-user name] run the web server | |
| 20 | + serve [-listen addr] [-host name] [-name text] [-open] [-ssh-user name] run the web server | |
| 21 | 21 | keys user home type key sshd AuthorizedKeysCommand |
| 22 | 22 | shell user forced command for ssh git access |
| 23 | 23 | invite print a single use registration code |
| @@ -173,13 +173,14 @@ func serve(root string, args []string) { | ||
| 173 | 173 | fs := flag.NewFlagSet("serve", flag.ExitOnError) |
| 174 | 174 | listen := fs.String("listen", "127.0.0.1:3200", "address to listen on") |
| 175 | 175 | host := fs.String("host", "localhost", "public hostname used in clone urls") |
| 176 | + name := fs.String("name", "gitpocket", "site name shown in the header") | |
| 176 | 177 | open := fs.Bool("open", false, "allow registration without an invite") |
| 177 | 178 | sshUser := fs.String("ssh-user", "git", "unix user that serves git over ssh, shown in clone urls") |
| 178 | 179 | fs.Parse(args) |
| 179 | 180 | store := mustStore(root) |
| 180 | 181 | srv := &http.Server{ |
| 181 | 182 | Addr: *listen, |
| 182 | - Handler: newServer(store, root, *host, *open, *sshUser).handler(), | |
| 183 | + Handler: newServer(store, root, *host, *name, *open, *sshUser).handler(), | |
| 183 | 184 | ReadHeaderTimeout: 10 * time.Second, |
| 184 | 185 | } |
| 185 | 186 | log.Printf("gitpocket listening on %s for %s", *listen, *host) |
static/style.css modified
| @@ -292,7 +292,7 @@ a.label{opacity:.75}a.label.on,a.label:hover{opacity:1;text-decoration:none} | ||
| 292 | 292 | .linkbutton{background:none;border:0;padding:0;font:inherit;color:var(--muted);cursor:pointer} |
| 293 | 293 | .linkbutton:hover{color:var(--del);text-decoration:underline} |
| 294 | 294 | nav.site .brand{display:inline-flex;align-items:center;gap:.4rem} |
| 295 | -.logo{width:1.45rem;height:1.45rem;fill:var(--fg)}.logo .wave{fill:none;stroke:var(--fg);stroke-width:2;stroke-linecap:round} | |
| 295 | +.logo{width:1.75rem;height:1.75rem;fill:#fff}.logo .pocket{fill:var(--fg)}.logo .branch{fill:none;stroke:#fff;stroke-width:1.5;stroke-linecap:round} | |
| 296 | 296 | .landing{margin:0} |
| 297 | 297 | .landing>p{margin:.2rem 0 1rem} |
| 298 | 298 | .landing a.arrow{text-decoration:underline} |
templates/layout.html modified
| @@ -17,7 +17,7 @@ | ||
| 17 | 17 | <body{{if .Fluid}} class="fluid"{{end}}> |
| 18 | 18 | <header> |
| 19 | 19 | <nav class="site"> |
| 20 | -<a class="brand" href="/"><svg class="logo" viewBox="0 0 24 24" aria-hidden="true"><path class="wave" d="M3 6.5c1.5-1.6 3-1.6 4.5 0s3 1.6 4.5 0 3-1.6 4.5 0 3 1.6 4.5 0"/><path d="M2.5 10.5h19a9.5 9.5 0 0 1-19 0z"/></svg>{{.Host}}</a> | |
| 20 | +<a class="brand" href="/"><svg class="logo" viewBox="0 0 24 24" aria-hidden="true"><path class="pocket" d="M3.5 3.5h17v9.5c0 4.4-3.8 8-8.5 8s-8.5-3.6-8.5-8z"/><circle cx="9" cy="9" r="1.6"/><circle cx="9" cy="16" r="1.6"/><circle cx="15" cy="11.5" r="1.6"/><path class="branch" d="M9 10.6v3.8M15 13.1c0 1.6-2.2 2.2-4.4 2.6"/></svg>{{.Name}}</a> | |
| 21 | 21 | <a href="/projects">projects</a> |
| 22 | 22 | <span class="spacer"></span> |
| 23 | 23 | {{if .User}}<span>Logged in as <a href="/~{{.User.Name}}">~{{.User.Name}}</a> — <form method="post" action="/logout"><button>Log out</button></form></span>{{else}}<span class="auth"><a href="/login">Log in</a> — <a href="/register">Register</a></span>{{end}} |
web.go modified
| @@ -44,6 +44,7 @@ type Server struct { | ||
| 44 | 44 | store *Store |
| 45 | 45 | root string |
| 46 | 46 | host string |
| 47 | + name string | |
| 47 | 48 | sshUser string |
| 48 | 49 | open bool |
| 49 | 50 | pages map[string]*template.Template |
| @@ -57,14 +58,15 @@ type page struct { | ||
| 57 | 58 | Title string |
| 58 | 59 | User *User |
| 59 | 60 | Host string |
| 61 | + Name string | |
| 60 | 62 | SSHUser string |
| 61 | 63 | Error string |
| 62 | 64 | Math bool |
| 63 | 65 | Data any |
| 64 | 66 | } |
| 65 | 67 | |
| 66 | -func newServer(store *Store, root, host string, open bool, sshUser string) *Server { | |
| 67 | - s := &Server{store: store, root: root, host: host, open: open, sshUser: sshUser, mailer: loadMailer(root), pages: map[string]*template.Template{}, limiter: newLimiter(10, 5*time.Minute)} | |
| 68 | +func newServer(store *Store, root, host, name string, open bool, sshUser string) *Server { | |
| 69 | + s := &Server{store: store, root: root, host: host, name: name, open: open, sshUser: sshUser, mailer: loadMailer(root), pages: map[string]*template.Template{}, limiter: newLimiter(10, 5*time.Minute)} | |
| 68 | 70 | funcs := template.FuncMap{ |
| 69 | 71 | "short": func(h string) string { |
| 70 | 72 | if len(h) > 10 { |
| @@ -135,6 +137,7 @@ func newServer(store *Store, root, host string, open bool, sshUser string) *Serv | ||
| 135 | 137 | |
| 136 | 138 | func (s *Server) render(w http.ResponseWriter, r *http.Request, name string, p page) { |
| 137 | 139 | p.Host = s.host |
| 140 | + p.Name = s.name | |
| 138 | 141 | p.SSHUser = s.sshUser |
| 139 | 142 | p.Version = s.version |
| 140 | 143 | if d, ok := p.Data.(map[string]any); ok && d["File"] == true { |