mirror of
https://github.com/tiennm99/ghglance.git
synced 2026-10-11 03:13:20 +00:00
`ghglance -serve :8080` runs a web UI from the same binary: submit a username, a background job renders every card in every theme, and /u/<user> shows them again with a theme picker and embed URLs. - Cards are stored on disk with atomic symlink publishing and deleted after -retention (default 24h); -cooldown limits token-less regeneration. - Token-less jobs use a public-only server token with private and org scope forced off; a submitter's own token is used for that job only and never stored or logged. The form links to GitHub's new-token page with the needed scopes pre-ticked. - The CLI and web share one fetch helper; CLI output is unchanged. - compose.yml deploys to Coolify with a data volume and /healthz check.
72 lines
2.6 KiB
HTML
72 lines
2.6 KiB
HTML
{{define "content"}}
|
|
<section class="user-head">
|
|
<h1>{{.Login}}</h1>
|
|
<p class="meta">
|
|
{{if .Meta}}Generated {{fmtTime .Meta.GeneratedAt}}
|
|
· {{.Meta.Scope}} data
|
|
· {{.Meta.Options.TZ}}
|
|
· week starts {{.Meta.Options.StartOfWeek}}
|
|
· {{end}}<a href="https://github.com/{{.Key}}" rel="noopener">GitHub profile</a>
|
|
</p>
|
|
</section>
|
|
|
|
{{if .Notice}}<p class="alert alert-info" role="status">{{.Notice}}</p>{{end}}
|
|
|
|
{{if .Job.Active}}
|
|
<div class="alert alert-progress" id="progress" data-status-url="/u/{{.Key}}/status">
|
|
<span class="spinner" aria-hidden="true"></span>
|
|
<div>
|
|
<p id="progress-text" role="status" aria-live="polite">{{if eq .Job.State "queued"}}Queued{{if .Job.Position}}, position {{.Job.Position}}{{end}}{{else}}Running: {{.Job.Stage}}{{end}}</p>
|
|
<p class="hint" id="progress-elapsed"></p>
|
|
<p class="hint">Large profiles take a few minutes. This page refreshes when the cards are ready.</p>
|
|
</div>
|
|
</div>
|
|
{{else if eq .Job.State "failed"}}
|
|
<p class="alert alert-error" role="alert">The last generation failed: {{.Job.Error}}</p>
|
|
{{end}}
|
|
|
|
{{if .Meta}}
|
|
<form class="toolbar" method="get" action="/u/{{.Key}}">
|
|
<label for="theme">Theme</label>
|
|
<select id="theme" name="theme">
|
|
{{range .Themes}}<option value="{{.}}"{{if eq . $.Theme}} selected{{end}}>{{.}}</option>
|
|
{{end}}
|
|
</select>
|
|
<button type="submit">Apply</button>
|
|
</form>
|
|
|
|
<ul class="cards">
|
|
{{range .Cards}}
|
|
<li class="card">
|
|
<figure>
|
|
<div class="card-image"><img src="{{.Src}}" alt="{{.Name}} card for {{$.Login}}" loading="lazy" decoding="async"></div>
|
|
<figcaption>
|
|
<span class="card-name">{{.Name}}</span>
|
|
<div class="copy-row">
|
|
<input type="text" readonly value="{{.URL}}" aria-label="Embed URL for the {{.Name}} card">
|
|
<button type="button" data-copy="{{.URL}}">Copy</button>
|
|
</div>
|
|
</figcaption>
|
|
</figure>
|
|
</li>
|
|
{{end}}
|
|
</ul>
|
|
|
|
<section class="panel">
|
|
<h2>Embed every card</h2>
|
|
<label for="markdown">Markdown for a README ({{.Theme}})</label>
|
|
<textarea id="markdown" readonly rows="8" spellcheck="false">{{.Markdown}}</textarea>
|
|
<button type="button" data-copy-target="markdown">Copy Markdown</button>
|
|
</section>
|
|
{{end}}
|
|
|
|
{{if not .Job.Active}}
|
|
<section class="panel">
|
|
<h2>{{if .Meta}}Regenerate{{else}}Try again{{end}}</h2>
|
|
{{if .ExpiresIn}}<p class="hint">These cards are deleted in about {{.ExpiresIn}}; regenerate to keep embedded links working.</p>{{end}}
|
|
{{if .CooldownLeft}}<p class="hint">Without a token these cards can be regenerated in {{.CooldownLeft}}. With your own token you can regenerate now.</p>{{end}}
|
|
{{template "form" .}}
|
|
</section>
|
|
{{end}}
|
|
{{end}}
|