Files
byre/mac/palette/main.go
T

96 lines
2.5 KiB
Go

package main
import (
"fmt"
"log"
"os"
"regexp"
"strings"
)
var (
property = regexp.MustCompile(`^\s*--([a-z0-9-]+):\s*#([0-9a-f]{6});\s*$`)
darkOpen = regexp.MustCompile(`^@media \(prefers-color-scheme: dark\) \{$`)
)
func block(lines []string, start int) (map[string]string, []string) {
colors := map[string]string{}
order := []string{}
for _, line := range lines[start+1:] {
if strings.TrimSpace(line) == "}" {
return colors, order
}
m := property.FindStringSubmatch(line)
if m == nil {
continue
}
colors[m[1]] = m[2]
order = append(order, m[1])
}
log.Fatalf("unterminated block at line %d", start+1)
return nil, nil
}
func swiftName(prop string) string {
parts := strings.Split(prop, "-")
for i := 1; i < len(parts); i++ {
parts[i] = strings.ToUpper(parts[i][:1]) + parts[i][1:]
}
return strings.Join(parts, "")
}
func main() {
css, err := os.ReadFile("../web/style.css")
if err != nil {
log.Fatal(err)
}
lines := strings.Split(string(css), "\n")
lightAt, darkAt := -1, -1
for i, line := range lines {
if line == ":root {" && lightAt < 0 {
lightAt = i
}
if darkOpen.MatchString(line) && i+1 < len(lines) && strings.TrimSpace(lines[i+1]) == ":root {" {
darkAt = i + 1
}
}
if lightAt < 0 || darkAt < 0 {
log.Fatal("web/style.css has no :root block or no prefers-color-scheme: dark :root block")
}
light, order := block(lines, lightAt)
dark, _ := block(lines, darkAt)
var b strings.Builder
b.WriteString("// Code generated by go generate ./mac from web/style.css. DO NOT EDIT.\n\n")
b.WriteString("import AppKit\nimport SwiftUI\n\n")
b.WriteString("enum Palette {\n")
for _, prop := range order {
d, ok := dark[prop]
if !ok {
log.Fatalf("--%s has no dark value", prop)
}
fmt.Fprintf(&b, " static let %s = dynamic(0x%s, 0x%s)\n", swiftName(prop), light[prop], d)
}
for prop := range dark {
if _, ok := light[prop]; !ok {
log.Fatalf("--%s has no light value", prop)
}
}
b.WriteString(`
private static func rgb(_ hex: UInt32) -> NSColor {
NSColor(srgbRed: CGFloat(hex >> 16 & 0xff) / 255, green: CGFloat(hex >> 8 & 0xff) / 255, blue: CGFloat(hex & 0xff) / 255, alpha: 1)
}
private static func dynamic(_ light: UInt32, _ dark: UInt32) -> Color {
Color(nsColor: NSColor(name: nil) { appearance in
appearance.bestMatch(from: [.aqua, .darkAqua]) == .darkAqua ? rgb(dark) : rgb(light)
})
}
}
`)
err = os.WriteFile("Sources/Byre/Palette.swift", []byte(b.String()), 0o644)
if err != nil {
log.Fatal(err)
}
}