package html
import (
"encoding/json"
"fmt"
"strings"
"github.com/bnema/vev-vt/core"
)
// Theme contains generic terminal colors. Consumers can override the same CSS
// custom properties directly when product-specific theme ownership is needed.
type Theme struct {
Foreground core.RGB
Background core.RGB
Cursor core.RGB
Selection core.RGB
SelectionText core.RGB
Palette [16]core.RGB
}
// MarshalJSON emits the typed object accepted by the embedded browser
// runtime's setTheme method.
func (theme Theme) MarshalJSON() ([]byte, error) {
palette := [16]RGB{}
for index, color := range theme.Palette {
palette[index] = browserRGB(color)
}
return json.Marshal(struct {
Foreground RGB `json:"foreground"`
Background RGB `json:"background"`
Cursor RGB `json:"cursor"`
Selection RGB `json:"selection"`
SelectionText RGB `json:"selectionText"`
Palette [16]RGB `json:"palette"`
}{
Foreground: browserRGB(theme.Foreground), Background: browserRGB(theme.Background),
Cursor: browserRGB(theme.Cursor), Selection: browserRGB(theme.Selection),
SelectionText: browserRGB(theme.SelectionText), Palette: palette,
})
}
func browserRGB(color core.RGB) RGB { return RGB{R: color.R, G: color.G, B: color.B} }
// DefaultTheme returns a neutral dark terminal theme.
func DefaultTheme() Theme {
return Theme{
Foreground: rgb(0xd8, 0xde, 0xe9),
Background: rgb(0x10, 0x12, 0x18),
Cursor: rgb(0xff, 0x87, 0x00),
Selection: rgb(0x39, 0x41, 0x50),
SelectionText: rgb(0xff, 0xff, 0xff),
Palette: [16]core.RGB{
rgb(0x00, 0x00, 0x00), rgb(0x80, 0x00, 0x00), rgb(0x00, 0x80, 0x00), rgb(0x80, 0x80, 0x00),
rgb(0x00, 0x00, 0x80), rgb(0x80, 0x00, 0x80), rgb(0x00, 0x80, 0x80), rgb(0xc0, 0xc0, 0xc0),
rgb(0x80, 0x80, 0x80), rgb(0xff, 0x00, 0x00), rgb(0x00, 0xff, 0x00), rgb(0xff, 0xff, 0x00),
rgb(0x00, 0x00, 0xff), rgb(0xff, 0x00, 0xff), rgb(0x00, 0xff, 0xff), rgb(0xff, 0xff, 0xff),
},
}
}
func rgb(r, g, b uint8) core.RGB { return core.RGB{R: r, G: g, B: b} }
// CSS returns deterministic custom-property declarations containing only
// numeric RGB values.
func (theme Theme) CSS() string {
var builder strings.Builder
builder.WriteString("--vev-fg:")
writeRGB(&builder, theme.Foreground)
builder.WriteString(";--vev-bg:")
writeRGB(&builder, theme.Background)
builder.WriteString(";--vev-cursor:")
writeRGB(&builder, theme.Cursor)
builder.WriteString(";--vev-selection-bg:")
writeRGB(&builder, theme.Selection)
builder.WriteString(";--vev-selection-fg:")
writeRGB(&builder, theme.SelectionText)
for index, color := range theme.Palette {
fmt.Fprintf(&builder, ";--vev-color-%d:", index)
writeRGB(&builder, color)
}
builder.WriteByte(';')
return builder.String()
}
func writeRGB(builder *strings.Builder, color core.RGB) {
fmt.Fprintf(builder, "#%02x%02x%02x", color.R, color.G, color.B)
}