96 lines
2.5 KiB
Go
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)
|
|
}
|
|
}
|