diff --git a/README.md b/README.md index 569d6074..88f59e14 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ jobs: with: user: ${{ github.repository_owner }} token: ${{ secrets.GHSTATS_TOKEN }} # classic PAT with read:user + repo - themes: dracula,github-dark,tokyonight + themes: dracula,github_dark,tokyonight tz: Asia/Saigon commit_changes: "true" ``` @@ -87,7 +87,7 @@ Then: ```sh export GITHUB_TOKEN=ghp_xxx -ghstats -user tiennm99 -themes dracula,github-dark -tz Asia/Saigon -out output +ghstats -user tiennm99 -themes dracula,github_dark -tz Asia/Saigon -out output ``` | Flag | Default | Description | @@ -103,10 +103,11 @@ ghstats -user tiennm99 -themes dracula,github-dark -tz Asia/Saigon -out output ## Themes -Run `ghstats -list-themes` for the full list. Built-ins include `default`, -`dark`, `dracula`, `github`, `github-dark`, `tokyonight`, `onedark`, `nord`, -`gruvbox`, `radical`, `synthwave`, `monokai`, `solarized-dark`, -`solarized-light`, `transparent`, and more. +Run `ghstats -list-themes` for the full list (60+ themes ported from +github-profile-summary-cards). Built-ins include `default`, `dark`, `dracula`, +`github`, `github_dark`, `tokyonight`, `onedark`, `nord_dark`, `nord_bright`, +`gruvbox`, `radical`, `synthwave`, `monokai`, `solarized`, `solarized_dark`, +`transparent`, and more. ## Output @@ -129,9 +130,8 @@ access token with `read:user` and `repo`, save it as a repo secret (e.g. ## Credits & inspiration -- [**github-profile-summary-cards**](https://github.com/vn7n24fzkq/github-profile-summary-cards) by [@vn7n24fzkq](https://github.com/vn7n24fzkq) — card layout, theme set, and output structure. +- [**github-profile-summary-cards**](https://github.com/vn7n24fzkq/github-profile-summary-cards) by [@vn7n24fzkq](https://github.com/vn7n24fzkq) — card layout, chart styles, theme palette, and output structure. - [**profile-summary-for-github**](https://github.com/tipsy/profile-summary-for-github) by [@tipsy](https://github.com/tipsy) — the original profile-summary generator. -- [**github-readme-stats**](https://github.com/anuraghazra/github-readme-stats) by [@anuraghazra](https://github.com/anuraghazra) — theme palette reference. ## License diff --git a/internal/card/donut_chart.go b/internal/card/donut_chart.go index 50b82bf0..7b222cd4 100644 --- a/internal/card/donut_chart.go +++ b/internal/card/donut_chart.go @@ -30,7 +30,7 @@ func renderDonutCard(title string, stats []github.LangStat, t theme.Theme) []byt stats = collapseOther(stats, topN) var b strings.Builder - b.WriteString(header(width, height, t.Background, t.Title, title)) + b.WriteString(header(width, height, t.Background, t.Stroke, t.StrokeOpacity, t.Title, title)) if len(stats) == 0 { fmt.Fprintf(&b, ` diff --git a/internal/card/productive.go b/internal/card/productive.go index 519448e9..eb62f96b 100644 --- a/internal/card/productive.go +++ b/internal/card/productive.go @@ -29,7 +29,7 @@ func (productiveCard) SVG(p *github.Profile, t theme.Theme) ([]byte, error) { barW := float64(chartW-barGap*23) / 24.0 var b strings.Builder - b.WriteString(header(width, height, t.Background, t.Title, "Commits by Hour (last year)")) + b.WriteString(header(width, height, t.Background, t.Stroke, t.StrokeOpacity, t.Title, "Commits by Hour (last year)")) max := 0 for _, v := range p.Productive { diff --git a/internal/card/profile.go b/internal/card/profile.go index ac97f23e..64c70af3 100644 --- a/internal/card/profile.go +++ b/internal/card/profile.go @@ -20,7 +20,7 @@ func (profileCard) SVG(p *github.Profile, t theme.Theme) ([]byte, error) { ) var b strings.Builder - b.WriteString(header(width, height, t.Background, t.Title, title(p))) + b.WriteString(header(width, height, t.Background, t.Stroke, t.StrokeOpacity, t.Title, title(p))) // Key-value lines; skip empty fields to avoid blank rows. y := 75 diff --git a/internal/card/stats.go b/internal/card/stats.go index 5cf25647..b2ff6fde 100644 --- a/internal/card/stats.go +++ b/internal/card/stats.go @@ -28,7 +28,7 @@ func (statsCard) SVG(p *github.Profile, t theme.Theme) ([]byte, error) { } var b strings.Builder - b.WriteString(header(width, height, t.Background, t.Title, "Stats")) + b.WriteString(header(width, height, t.Background, t.Stroke, t.StrokeOpacity, t.Title, "Stats")) // 2×3 grid: columns at 25 and 265, rows every 42px starting at y=80. for i, it := range items { diff --git a/internal/card/svg.go b/internal/card/svg.go index 0bec1d98..21c4c5dc 100644 --- a/internal/card/svg.go +++ b/internal/card/svg.go @@ -53,12 +53,12 @@ func formatInt(n int) string { } // header returns the opening tag + background rect + title text. -func header(width, height int, bg, titleColor, title string) string { +func header(width, height int, bg, stroke string, strokeOpacity float64, titleColor, title string) string { return fmt.Sprintf(` - + %s`, width, height, width, height, - width-1, height-1, bg, + width-1, height-1, bg, stroke, strokeOpacity, titleColor, escapeXML(title)) } diff --git a/internal/theme/theme.go b/internal/theme/theme.go index b5a3ee55..e64fac62 100644 --- a/internal/theme/theme.go +++ b/internal/theme/theme.go @@ -1,57 +1,99 @@ // Package theme defines SVG color palettes used by card renderers. +// +// Palette data is ported from github-profile-summary-cards so visual output +// stays consistent with that project. package theme import "sort" // Theme describes the colors applied to a rendered card. type Theme struct { - ID string - Background string - Text string - Title string - Accent string - Muted string + ID string + Title string // card title text color + Text string // body text color + Background string // card background fill + Stroke string // card outline stroke + StrokeOpacity float64 // 0–1; 0 hides the outline + Muted string // axis / legend / secondary text + Accent string // bar, donut slice fallback, tick highlight } -// Built-in palettes. Port of a curated subset from github-readme-stats. +// Built-in palettes ported verbatim from +// github-profile-summary-cards/src/const/theme.ts. var themes = map[string]Theme{ - "default": {ID: "default", Background: "#fffefe", Text: "#434d58", Title: "#2f80ed", Accent: "#4c71f2", Muted: "#6a737d"}, - "dark": {ID: "dark", Background: "#151515", Text: "#9f9f9f", Title: "#fff", Accent: "#79ff97", Muted: "#666"}, - "radical": {ID: "radical", Background: "#141321", Text: "#a9fef7", Title: "#fe428e", Accent: "#f8d847", Muted: "#a9fef7"}, - "merko": {ID: "merko", Background: "#0b1p08", Text: "#68b684", Title: "#abd200", Accent: "#b7d364", Muted: "#68b684"}, - "gruvbox": {ID: "gruvbox", Background: "#282828", Text: "#fbf1c7", Title: "#fabd2f", Accent: "#8ec07c", Muted: "#a89984"}, - "tokyonight": {ID: "tokyonight", Background: "#1a1b27", Text: "#a9b1d6", Title: "#70a5fd", Accent: "#bf91f3", Muted: "#565f89"}, - "onedark": {ID: "onedark", Background: "#282c34", Text: "#aaa", Title: "#e4bf7a", Accent: "#8eb573", Muted: "#5c6370"}, - "cobalt": {ID: "cobalt", Background: "#193549", Text: "#dbe4ee", Title: "#e683d9", Accent: "#0088ff", Muted: "#6fc3df"}, - "synthwave": {ID: "synthwave", Background: "#2b213a", Text: "#e5289e", Title: "#e2e9ec", Accent: "#ef8539", Muted: "#e5289e"}, - "highcontrast": {ID: "highcontrast", Background: "#000000", Text: "#ffffff", Title: "#e7f216", Accent: "#00ffff", Muted: "#ffffff"}, - "dracula": {ID: "dracula", Background: "#282a36", Text: "#f8f8f2", Title: "#ff79c6", Accent: "#bd93f9", Muted: "#6272a4"}, - "prussian": {ID: "prussian", Background: "#172f45", Text: "#c8c9db", Title: "#bddfff", Accent: "#38b2ac", Muted: "#6c95b8"}, - "monokai": {ID: "monokai", Background: "#272822", Text: "#d6ebbf", Title: "#eb1f6a", Accent: "#e28905", Muted: "#75715e"}, - "vue": {ID: "vue", Background: "#fffefe", Text: "#476582", Title: "#41b883", Accent: "#35495e", Muted: "#476582"}, - "vue-dark": {ID: "vue-dark", Background: "#1d1f21", Text: "#bbb", Title: "#41b883", Accent: "#41b883", Muted: "#888"}, - "shades-of-purple":{ID: "shades-of-purple", Background: "#2d2b55", Text: "#a599e9", Title: "#fad000", Accent: "#b362ff", Muted: "#a599e9"}, - "nightowl": {ID: "nightowl", Background: "#011627", Text: "#acb4c2", Title: "#7fdbca", Accent: "#82aaff", Muted: "#637777"}, - "buefy": {ID: "buefy", Background: "#ffffff", Text: "#363636", Title: "#7957d5", Accent: "#ff3860", Muted: "#7a7a7a"}, - "blue-green": {ID: "blue-green", Background: "#040f0f", Text: "#2dd4bf", Title: "#afebcd", Accent: "#26a69a", Muted: "#5e8b7e"}, - "algolia": {ID: "algolia", Background: "#050f2c", Text: "#ffffff", Title: "#00aeff", Accent: "#2dde98", Muted: "#8c8c8c"}, - "great-gatsby": {ID: "great-gatsby", Background: "#000000", Text: "#ffd700", Title: "#ffa726", Accent: "#ffb74d", Muted: "#9e9e9e"}, - "darcula": {ID: "darcula", Background: "#242424", Text: "#ba5f17", Title: "#ba5f17", Accent: "#2f81f7", Muted: "#8b949e"}, - "bear": {ID: "bear", Background: "#1f2023", Text: "#8f9396", Title: "#e03c8a", Accent: "#00aeff", Muted: "#8f9396"}, - "solarized-dark": {ID: "solarized-dark", Background: "#002b36", Text: "#859900", Title: "#268bd2", Accent: "#d33682", Muted: "#586e75"}, - "solarized-light": {ID: "solarized-light", Background: "#fdf6e3", Text: "#657b83", Title: "#268bd2", Accent: "#d33682", Muted: "#93a1a1"}, - "chartreuse-dark": {ID: "chartreuse-dark", Background: "#000000", Text: "#ffffff", Title: "#7fff00", Accent: "#7fff00", Muted: "#5fcf00"}, - "nord": {ID: "nord", Background: "#2e3440", Text: "#d8dee9", Title: "#88c0d0", Accent: "#81a1c1", Muted: "#4c566a"}, - "github": {ID: "github", Background: "#ffffff", Text: "#24292f", Title: "#0969da", Accent: "#2188ff", Muted: "#57606a"}, - "github-dark": {ID: "github-dark", Background: "#0d1117", Text: "#c9d1d9", Title: "#58a6ff", Accent: "#3fb950", Muted: "#8b949e"}, - "transparent": {ID: "transparent", Background: "#00000000", Text: "#434d58", Title: "#2f80ed", Accent: "#4c71f2", Muted: "#6a737d"}, + "holi": {Title: "#5ea9eb", Text: "#d6e7ff", Background: "#030314", Stroke: "#d6e7ff", StrokeOpacity: 1, Muted: "#5090cb", Accent: "#5090cb"}, + "2077": {Title: "#ff0055", Text: "#03d8f3", Background: "#141321", Stroke: "#141321", StrokeOpacity: 1, Muted: "#fcee0c", Accent: "#00ffc8"}, + "algolia": {Title: "#00aeff", Text: "#ffffff", Background: "#050f2c", Stroke: "#000000", StrokeOpacity: 0, Muted: "#2dde98", Accent: "#00aeff"}, + "apprentice": {Title: "#ffffff", Text: "#bcbcbc", Background: "#262626", Stroke: "#000000", StrokeOpacity: 0, Muted: "#ffffaf", Accent: "#ffffff"}, + "aura_dark": {Title: "#ff7372", Text: "#dbdbdb", Background: "#252334", Stroke: "#000000", StrokeOpacity: 0, Muted: "#6cffd0", Accent: "#ff7372"}, + "aura": {Title: "#a277ff", Text: "#61ffca", Background: "#15141b", Stroke: "#000000", StrokeOpacity: 0, Muted: "#ffca85", Accent: "#a277ff"}, + "ayu_mirage": {Title: "#f4cd7c", Text: "#c7c8c2", Background: "#1f2430", Stroke: "#000000", StrokeOpacity: 0, Muted: "#73d0ff", Accent: "#f4cd7c"}, + "bear": {Title: "#e03c8a", Text: "#bcb28d", Background: "#1f2023", Stroke: "#000000", StrokeOpacity: 0, Muted: "#00aeff", Accent: "#e03c8a"}, + "blue_green": {Title: "#2f97c1", Text: "#0cf574", Background: "#040f0f", Stroke: "#000000", StrokeOpacity: 0, Muted: "#f5b700", Accent: "#2f97c1"}, + "blueberry": {Title: "#82aaff", Text: "#27e8a7", Background: "#242938", Stroke: "#000000", StrokeOpacity: 0, Muted: "#89ddff", Accent: "#82aaff"}, + "buefy": {Title: "#7957d5", Text: "#363636", Background: "#ffffff", Stroke: "#000000", StrokeOpacity: 0, Muted: "#ff3860", Accent: "#7957d5"}, + "calm": {Title: "#e07a5f", Text: "#ebcfb2", Background: "#373f51", Stroke: "#000000", StrokeOpacity: 0, Muted: "#edae49", Accent: "#e07a5f"}, + "chartreuse_dark": {Title: "#7fff00", Text: "#ffffff", Background: "#000000", Stroke: "#000000", StrokeOpacity: 1, Muted: "#00aeff", Accent: "#7fff00"}, + "city_lights": {Title: "#5d8cb3", Text: "#718ca1", Background: "#1d252c", Stroke: "#000000", StrokeOpacity: 0, Muted: "#4798ff", Accent: "#5d8cb3"}, + "cobalt": {Title: "#e683d9", Text: "#75eeb2", Background: "#193549", Stroke: "#000000", StrokeOpacity: 0, Muted: "#0480ef", Accent: "#e683d9"}, + "cobalt2": {Title: "#ffc600", Text: "#0088ff", Background: "#193549", Stroke: "#000000", StrokeOpacity: 0, Muted: "#ffffff", Accent: "#ffc600"}, + "codeSTACKr": {Title: "#ff652f", Text: "#ffffff", Background: "#09131b", Stroke: "#0c1a25", StrokeOpacity: 1, Muted: "#ffe400", Accent: "#ff652f"}, + "darcula": {Title: "#ba5f17", Text: "#bebebe", Background: "#242424", Stroke: "#000000", StrokeOpacity: 0, Muted: "#ffb74d", Accent: "#ba5f17"}, + "dark": {Title: "#ffffff", Text: "#9f9f9f", Background: "#151515", Stroke: "#000000", StrokeOpacity: 0, Muted: "#79ff97", Accent: "#ffffff"}, + "date_night": {Title: "#da7885", Text: "#e1b2a2", Background: "#170f0c", Stroke: "#170f0c", StrokeOpacity: 1, Muted: "#bb8470", Accent: "#da7885"}, + "default": {Title: "#586e75", Text: "#586e75", Background: "#ffffff", Stroke: "#e4e2e2", StrokeOpacity: 1, Muted: "#586e75", Accent: "#586e75"}, + "discord_old_blurple": {Title: "#7289da", Text: "#ffffff", Background: "#2c2f33", Stroke: "#000000", StrokeOpacity: 0, Muted: "#7289da", Accent: "#7289da"}, + "dracula": {Title: "#ff79c6", Text: "#ffb86c", Background: "#282a36", Stroke: "#282a36", StrokeOpacity: 1, Muted: "#6272a4", Accent: "#bd93f9"}, + "flag_india": {Title: "#ff8f1c", Text: "#509e2f", Background: "#ffffff", Stroke: "#000000", StrokeOpacity: 0, Muted: "#250e62", Accent: "#ff8f1c"}, + "github_dark": {Title: "#0366d6", Text: "#77909c", Background: "#0d1117", Stroke: "#2e343b", StrokeOpacity: 1, Muted: "#8b949e", Accent: "#40c463"}, + "github": {Title: "#0366d6", Text: "#586069", Background: "#ffffff", Stroke: "#e4e2e2", StrokeOpacity: 1, Muted: "#586069", Accent: "#40c463"}, + "gotham": {Title: "#2aa889", Text: "#99d1ce", Background: "#0c1014", Stroke: "#000000", StrokeOpacity: 1, Muted: "#599cab", Accent: "#2aa889"}, + "graywhite": {Title: "#24292e", Text: "#24292e", Background: "#ffffff", Stroke: "#000000", StrokeOpacity: 0, Muted: "#24292e", Accent: "#24292e"}, + "great_gatsby": {Title: "#ffa726", Text: "#ffd95b", Background: "#000000", Stroke: "#000000", StrokeOpacity: 0, Muted: "#ffb74d", Accent: "#ffa726"}, + "gruvbox": {Title: "#fabd2f", Text: "#8ec07c", Background: "#282828", Stroke: "#282828", StrokeOpacity: 1, Muted: "#fe8019", Accent: "#fe8019"}, + "highcontrast": {Title: "#e7f216", Text: "#ffffff", Background: "#000000", Stroke: "#000000", StrokeOpacity: 0, Muted: "#00ffff", Accent: "#e7f216"}, + "jolly": {Title: "#ff64da", Text: "#ffffff", Background: "#291b3e", Stroke: "#000000", StrokeOpacity: 0, Muted: "#a960ff", Accent: "#ff64da"}, + "kacho_ga": {Title: "#bf4a3f", Text: "#d9c8a9", Background: "#402b23", Stroke: "#000000", StrokeOpacity: 0, Muted: "#a64833", Accent: "#bf4a3f"}, + "maroongold": {Title: "#f7ef8a", Text: "#e0aa3e", Background: "#260000", Stroke: "#000000", StrokeOpacity: 0, Muted: "#f7ef8a", Accent: "#f7ef8a"}, + "material_palenight": {Title: "#c792ea", Text: "#a6accd", Background: "#292d3e", Stroke: "#000000", StrokeOpacity: 0, Muted: "#89ddff", Accent: "#c792ea"}, + "merko": {Title: "#abd200", Text: "#68b587", Background: "#0a0f0b", Stroke: "#000000", StrokeOpacity: 0, Muted: "#b7d364", Accent: "#abd200"}, + "midnight_purple": {Title: "#9745f5", Text: "#ffffff", Background: "#000000", Stroke: "#000000", StrokeOpacity: 0, Muted: "#9f4bff", Accent: "#9745f5"}, + "moltack": {Title: "#86092c", Text: "#574038", Background: "#f5e1c0", Stroke: "#000000", StrokeOpacity: 0, Muted: "#86092c", Accent: "#86092c"}, + "monokai": {Title: "#eb1f6a", Text: "#ffffff", Background: "#2c292d", Stroke: "#2c292d", StrokeOpacity: 1, Muted: "#e28905", Accent: "#ae81ff"}, + "moonlight": {Title: "#ff757f", Text: "#f8f8f8", Background: "#222436", Stroke: "#222436", StrokeOpacity: 1, Muted: "#599dff", Accent: "#ff757f"}, + "nightowl": {Title: "#c792ea", Text: "#7fdbca", Background: "#011627", Stroke: "#000000", StrokeOpacity: 0, Muted: "#ffeb95", Accent: "#c792ea"}, + "noctis_minimus": {Title: "#d3b692", Text: "#c5cdd3", Background: "#1b2932", Stroke: "#000000", StrokeOpacity: 0, Muted: "#72b7c0", Accent: "#d3b692"}, + "nord_bright": {Title: "#3b4252", Text: "#2e3440", Background: "#eceff4", Stroke: "#e5e9f0", StrokeOpacity: 1, Muted: "#8fbcbb", Accent: "#88c0d0"}, + "nord_dark": {Title: "#eceff4", Text: "#e5e9f0", Background: "#2e3440", Stroke: "#eceff4", StrokeOpacity: 1, Muted: "#8fbcbb", Accent: "#88c0d0"}, + "ocean_dark": {Title: "#8957b2", Text: "#92d534", Background: "#151a28", Stroke: "#000000", StrokeOpacity: 0, Muted: "#ffffff", Accent: "#8957b2"}, + "omni": {Title: "#ff79c6", Text: "#e1e1e6", Background: "#191622", Stroke: "#000000", StrokeOpacity: 0, Muted: "#e7de79", Accent: "#ff79c6"}, + "onedark": {Title: "#e4bf7a", Text: "#df6d74", Background: "#282c34", Stroke: "#000000", StrokeOpacity: 0, Muted: "#8eb573", Accent: "#e4bf7a"}, + "outrun": {Title: "#ffcc00", Text: "#8080ff", Background: "#141439", Stroke: "#000000", StrokeOpacity: 0, Muted: "#ff1aff", Accent: "#ffcc00"}, + "panda": {Title: "#19f9d899", Text: "#ff75b5", Background: "#31353a", Stroke: "#000000", StrokeOpacity: 0, Muted: "#19f9d899", Accent: "#19f9d899"}, + "prussian": {Title: "#bddfff", Text: "#6e93b5", Background: "#172f45", Stroke: "#000000", StrokeOpacity: 0, Muted: "#38a0ff", Accent: "#bddfff"}, + "radical": {Title: "#fe428e", Text: "#a9fef7", Background: "#141321", Stroke: "#141321", StrokeOpacity: 1, Muted: "#f8d847", Accent: "#ae81ff"}, + "react": {Title: "#61dafb", Text: "#ffffff", Background: "#20232a", Stroke: "#000000", StrokeOpacity: 0, Muted: "#61dafb", Accent: "#61dafb"}, + "rose_pine": {Title: "#9ccfd8", Text: "#e0def4", Background: "#191724", Stroke: "#000000", StrokeOpacity: 0, Muted: "#ebbcba", Accent: "#9ccfd8"}, + "shades_of_purple": {Title: "#fad000", Text: "#a599e9", Background: "#2d2b55", Stroke: "#000000", StrokeOpacity: 0, Muted: "#b362ff", Accent: "#fad000"}, + "slateorange": {Title: "#faa627", Text: "#ffffff", Background: "#36393f", Stroke: "#000000", StrokeOpacity: 0, Muted: "#faa627", Accent: "#faa627"}, + "solarized_dark": {Title: "#268bd2", Text: "#839496", Background: "#073642", Stroke: "#073642", StrokeOpacity: 1, Muted: "#b58900", Accent: "#859900"}, + "solarized": {Title: "#268bd2", Text: "#586e75", Background: "#fdf6e3", Stroke: "#fdf6e3", StrokeOpacity: 1, Muted: "#b58900", Accent: "#859900"}, + "swift": {Title: "#000000", Text: "#000000", Background: "#f7f7f7", Stroke: "#000000", StrokeOpacity: 0, Muted: "#f05237", Accent: "#000000"}, + "synthwave": {Title: "#e2e9ec", Text: "#e5289e", Background: "#2b213a", Stroke: "#000000", StrokeOpacity: 0, Muted: "#ef8539", Accent: "#e2e9ec"}, + "tokyonight": {Title: "#70a5fd", Text: "#38bdae", Background: "#1a1b27", Stroke: "#1a1b27", StrokeOpacity: 1, Muted: "#bf91f3", Accent: "#bf91f3"}, + "transparent": {Title: "#006AFF", Text: "#417E87", Background: "#00000000", Stroke: "#000000", StrokeOpacity: 0, Muted: "#0579C3", Accent: "#006AFF"}, + "vision_friendly_dark": {Title: "#ffb000", Text: "#ffffff", Background: "#000000", Stroke: "#000000", StrokeOpacity: 0, Muted: "#785ef0", Accent: "#ffb000"}, + "vue": {Title: "#41b883", Text: "#000000", Background: "#ffffff", Stroke: "#e4e2e2", StrokeOpacity: 1, Muted: "#41b883", Accent: "#41b883"}, + "yeblu": {Title: "#ffff00", Text: "#ffffff", Background: "#002046", Stroke: "#000000", StrokeOpacity: 0, Muted: "#ffff00", Accent: "#ffff00"}, + "zenburn": {Title: "#f0dfaf", Text: "#dcdccc", Background: "#3f3f3f", Stroke: "#3f3f3f", StrokeOpacity: 1, Muted: "#8cd0d3", Accent: "#7f9f7f"}, } -// merko had a typo fixed at init. func init() { - m := themes["merko"] - m.Background = "#0b1708" - themes["merko"] = m + // Populate ID fields from the map key so callers can read theme.ID. + for id, t := range themes { + t.ID = id + themes[id] = t + } } // Lookup returns the theme with the given id.