1package html
2
3import (
4 "encoding/json"
5 "fmt"
6 "strings"
7
8 "github.com/bnema/vev-vt/core"
9)
10
11// Theme contains generic terminal colors. Consumers can override the same CSS
12// custom properties directly when product-specific theme ownership is needed.
13type Theme struct {
14 Foreground core.RGB
15 Background core.RGB
16 Cursor core.RGB
17 Selection core.RGB
18 SelectionText core.RGB
19 Palette [16]core.RGB
20}
21
22// MarshalJSON emits the typed object accepted by the embedded browser
23// runtime's setTheme method.
24func (theme Theme) MarshalJSON() ([]byte, error) {
25 palette := [16]RGB{}
26 for index, color := range theme.Palette {
27 palette[index] = browserRGB(color)
28 }
29 return json.Marshal(struct {
30 Foreground RGB `json:"foreground"`
31 Background RGB `json:"background"`
32 Cursor RGB `json:"cursor"`
33 Selection RGB `json:"selection"`
34 SelectionText RGB `json:"selectionText"`
35 Palette [16]RGB `json:"palette"`
36 }{
37 Foreground: browserRGB(theme.Foreground), Background: browserRGB(theme.Background),
38 Cursor: browserRGB(theme.Cursor), Selection: browserRGB(theme.Selection),
39 SelectionText: browserRGB(theme.SelectionText), Palette: palette,
40 })
41}
42
43func browserRGB(color core.RGB) RGB { return RGB{R: color.R, G: color.G, B: color.B} }
44
45// DefaultTheme returns a neutral dark terminal theme.
46func DefaultTheme() Theme {
47 return Theme{
48 Foreground: rgb(0xd8, 0xde, 0xe9),
49 Background: rgb(0x10, 0x12, 0x18),
50 Cursor: rgb(0xff, 0x87, 0x00),
51 Selection: rgb(0x39, 0x41, 0x50),
52 SelectionText: rgb(0xff, 0xff, 0xff),
53 Palette: [16]core.RGB{
54 rgb(0x00, 0x00, 0x00), rgb(0x80, 0x00, 0x00), rgb(0x00, 0x80, 0x00), rgb(0x80, 0x80, 0x00),
55 rgb(0x00, 0x00, 0x80), rgb(0x80, 0x00, 0x80), rgb(0x00, 0x80, 0x80), rgb(0xc0, 0xc0, 0xc0),
56 rgb(0x80, 0x80, 0x80), rgb(0xff, 0x00, 0x00), rgb(0x00, 0xff, 0x00), rgb(0xff, 0xff, 0x00),
57 rgb(0x00, 0x00, 0xff), rgb(0xff, 0x00, 0xff), rgb(0x00, 0xff, 0xff), rgb(0xff, 0xff, 0xff),
58 },
59 }
60}
61
62func rgb(r, g, b uint8) core.RGB { return core.RGB{R: r, G: g, B: b} }
63
64// CSS returns deterministic custom-property declarations containing only
65// numeric RGB values.
66func (theme Theme) CSS() string {
67 var builder strings.Builder
68 builder.WriteString("--vev-fg:")
69 writeRGB(&builder, theme.Foreground)
70 builder.WriteString(";--vev-bg:")
71 writeRGB(&builder, theme.Background)
72 builder.WriteString(";--vev-cursor:")
73 writeRGB(&builder, theme.Cursor)
74 builder.WriteString(";--vev-selection-bg:")
75 writeRGB(&builder, theme.Selection)
76 builder.WriteString(";--vev-selection-fg:")
77 writeRGB(&builder, theme.SelectionText)
78 for index, color := range theme.Palette {
79 fmt.Fprintf(&builder, ";--vev-color-%d:", index)
80 writeRGB(&builder, color)
81 }
82 builder.WriteByte(';')
83 return builder.String()
84}
85
86func writeRGB(builder *strings.Builder, color core.RGB) {
87 fmt.Fprintf(builder, "#%02x%02x%02x", color.R, color.G, color.B)
88}