Rewrite in Go: static binaries, zero runtime dependencies
Some checks failed
Release / build (push) Failing after 21s
Some checks failed
Release / build (push) Failing after 21s
Replace Node.js + Python codebase with three Go binaries: - claude-statusline: CLI status bar for Claude Code - claude-fetcher: standalone cron job for API usage - claude-widget: system tray icon (fyne-io/systray + fogleman/gg) All CGO-free for trivial cross-compilation. Add nfpm .deb packaging with autostart and cron. CI pipeline produces Linux + Windows binaries, .deb, .tar.gz, and .zip release assets. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
125
internal/renderer/renderer.go
Normal file
125
internal/renderer/renderer.go
Normal file
@@ -0,0 +1,125 @@
|
||||
package renderer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"math"
|
||||
|
||||
"github.com/fogleman/gg"
|
||||
)
|
||||
|
||||
const iconSize = 256
|
||||
|
||||
// Claude orange for the starburst logo.
|
||||
var claudeOrange = color.RGBA{224, 123, 83, 255}
|
||||
|
||||
// arcColors maps usage percentage thresholds to colors.
|
||||
var arcColors = []struct {
|
||||
threshold int
|
||||
color color.RGBA
|
||||
}{
|
||||
{10, color.RGBA{76, 175, 80, 255}}, // green
|
||||
{20, color.RGBA{67, 160, 71, 255}}, // darker green
|
||||
{30, color.RGBA{124, 179, 66, 255}}, // light green
|
||||
{40, color.RGBA{192, 202, 51, 255}}, // lime
|
||||
{50, color.RGBA{253, 216, 53, 255}}, // yellow
|
||||
{60, color.RGBA{255, 193, 7, 255}}, // amber
|
||||
{70, color.RGBA{255, 179, 0, 255}}, // darker amber
|
||||
{80, color.RGBA{255, 152, 0, 255}}, // orange
|
||||
{90, color.RGBA{255, 87, 34, 255}}, // deep orange
|
||||
{100, color.RGBA{244, 67, 54, 255}}, // red
|
||||
}
|
||||
|
||||
func getArcColor(pct int) color.RGBA {
|
||||
for _, ac := range arcColors {
|
||||
if pct <= ac.threshold {
|
||||
return ac.color
|
||||
}
|
||||
}
|
||||
return arcColors[len(arcColors)-1].color
|
||||
}
|
||||
|
||||
// drawStarburst draws the 8-petal Claude logo.
|
||||
func drawStarburst(dc *gg.Context) {
|
||||
cx := float64(iconSize) / 2
|
||||
cy := float64(iconSize) / 2
|
||||
petalLen := float64(iconSize) * 0.38
|
||||
petalWidth := float64(iconSize) * 0.10
|
||||
centerRadius := float64(iconSize) * 0.04
|
||||
|
||||
dc.SetColor(claudeOrange)
|
||||
|
||||
for i := 0; i < 8; i++ {
|
||||
angle := float64(i) * (2 * math.Pi / 8)
|
||||
|
||||
// Tip of the petal
|
||||
tipX := cx + petalLen*math.Cos(angle)
|
||||
tipY := cy + petalLen*math.Sin(angle)
|
||||
|
||||
// Base points (perpendicular to angle)
|
||||
perpAngle := angle + math.Pi/2
|
||||
baseX1 := cx + petalWidth*math.Cos(perpAngle)
|
||||
baseY1 := cy + petalWidth*math.Sin(perpAngle)
|
||||
baseX2 := cx - petalWidth*math.Cos(perpAngle)
|
||||
baseY2 := cy - petalWidth*math.Sin(perpAngle)
|
||||
|
||||
// Inner point (slightly behind center for petal shape)
|
||||
innerX := cx - petalWidth*0.5*math.Cos(angle)
|
||||
innerY := cy - petalWidth*0.5*math.Sin(angle)
|
||||
|
||||
dc.MoveTo(innerX, innerY)
|
||||
dc.LineTo(baseX1, baseY1)
|
||||
dc.LineTo(tipX, tipY)
|
||||
dc.LineTo(baseX2, baseY2)
|
||||
dc.ClosePath()
|
||||
dc.Fill()
|
||||
}
|
||||
|
||||
// Center dot
|
||||
dc.DrawCircle(cx, cy, centerRadius)
|
||||
dc.Fill()
|
||||
}
|
||||
|
||||
// drawArc draws a circular progress arc.
|
||||
func drawArc(dc *gg.Context, pct int) {
|
||||
if pct <= 0 {
|
||||
return
|
||||
}
|
||||
if pct > 100 {
|
||||
pct = 100
|
||||
}
|
||||
|
||||
cx := float64(iconSize) / 2
|
||||
cy := float64(iconSize) / 2
|
||||
radius := float64(iconSize)/2 - 14 // inset from edge
|
||||
arcWidth := 28.0
|
||||
|
||||
startAngle := -math.Pi / 2 // 12 o'clock
|
||||
endAngle := startAngle + (float64(pct)/100)*2*math.Pi
|
||||
|
||||
dc.SetColor(getArcColor(pct))
|
||||
dc.SetLineWidth(arcWidth)
|
||||
dc.SetLineCap(gg.LineCapButt)
|
||||
dc.DrawArc(cx, cy, radius, startAngle, endAngle)
|
||||
dc.Stroke()
|
||||
}
|
||||
|
||||
// RenderIcon generates a 256x256 PNG icon with starburst and usage arc.
|
||||
func RenderIcon(pct int) image.Image {
|
||||
dc := gg.NewContext(iconSize, iconSize)
|
||||
drawStarburst(dc)
|
||||
drawArc(dc, pct)
|
||||
return dc.Image()
|
||||
}
|
||||
|
||||
// RenderIconPNG generates the icon as PNG bytes (for systray).
|
||||
func RenderIconPNG(pct int) ([]byte, error) {
|
||||
img := RenderIcon(pct)
|
||||
var buf bytes.Buffer
|
||||
if err := png.Encode(&buf, img); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user