138 lines
2.3 KiB
Go
138 lines
2.3 KiB
Go
|
package webcontroller
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
)
|
||
|
|
||
|
type Color interface {
|
||
|
CSS() string
|
||
|
}
|
||
|
|
||
|
// Raw CSS
|
||
|
type CSS string
|
||
|
|
||
|
func (c CSS) CSS() string { return string(c) }
|
||
|
|
||
|
const NoColor = CSS("none")
|
||
|
|
||
|
// HSL color
|
||
|
type hsl struct {
|
||
|
Hue int
|
||
|
Saturation float64
|
||
|
Lightness float64
|
||
|
}
|
||
|
|
||
|
func (orig hsl) RGB() string {
|
||
|
var r, g, b, q, p float64
|
||
|
var h, s, l = float64(orig.Hue) / 360, orig.Saturation, orig.Lightness
|
||
|
|
||
|
if s == 0 {
|
||
|
r, g, b = l, l, l
|
||
|
} else {
|
||
|
var hue2rgb = func(p, q, t float64) float64 {
|
||
|
if t < 0 {
|
||
|
t++
|
||
|
}
|
||
|
if t > 1 {
|
||
|
t--
|
||
|
}
|
||
|
|
||
|
if t < 1.0/6.0 {
|
||
|
return p + (q-p)*6*t
|
||
|
} else if t < 1.0/2.0 {
|
||
|
return q
|
||
|
} else if t < 2.0/3.0 {
|
||
|
return p + (q-p)*(2.0/3.0-t)*6
|
||
|
}
|
||
|
return p
|
||
|
}
|
||
|
|
||
|
if l < 0.5 {
|
||
|
q = l * (1 + s)
|
||
|
} else {
|
||
|
q = l + s - l*s
|
||
|
}
|
||
|
|
||
|
p = 2*l - q
|
||
|
r = hue2rgb(p, q, h+1.0/3.0)
|
||
|
g = hue2rgb(p, q, h)
|
||
|
b = hue2rgb(p, q, h-1.0/3.0)
|
||
|
}
|
||
|
|
||
|
return fmt.Sprintf("%02x%02x%02x", int(r*255), int(g*255), int(b*255))
|
||
|
}
|
||
|
func (orig hsl) CSS() string {
|
||
|
return "#" + orig.RGB()
|
||
|
}
|
||
|
|
||
|
// Add returns a NEW HSL struct, it doesn't modify the current one
|
||
|
func (h hsl) Add(hue int, saturation float64, lightness float64) hsl {
|
||
|
var new = hsl{
|
||
|
h.Hue + hue,
|
||
|
h.Saturation + saturation,
|
||
|
h.Lightness + lightness,
|
||
|
}
|
||
|
// Hue bounds correction
|
||
|
if new.Hue < 0 {
|
||
|
new.Hue += 360
|
||
|
} else if new.Hue > 360 {
|
||
|
new.Hue -= 360
|
||
|
}
|
||
|
// Saturation bounds check
|
||
|
if new.Saturation < 0 {
|
||
|
new.Saturation = 0
|
||
|
} else if new.Saturation > 1 {
|
||
|
new.Saturation = 1
|
||
|
}
|
||
|
// Lightness bounds check
|
||
|
if new.Lightness < 0 {
|
||
|
new.Lightness = 0
|
||
|
} else if new.Lightness > 1 {
|
||
|
new.Lightness = 1
|
||
|
}
|
||
|
|
||
|
return new
|
||
|
}
|
||
|
|
||
|
type RGB struct {
|
||
|
R uint8
|
||
|
G uint8
|
||
|
B uint8
|
||
|
}
|
||
|
|
||
|
func (rgb RGB) CSS() string {
|
||
|
return fmt.Sprintf("#%02x%02x%02x", rgb.R, rgb.G, rgb.B)
|
||
|
}
|
||
|
|
||
|
type RGBA struct {
|
||
|
R uint8
|
||
|
G uint8
|
||
|
B uint8
|
||
|
A float64
|
||
|
}
|
||
|
|
||
|
func (rgba RGBA) CSS() string {
|
||
|
return fmt.Sprintf("rgba(%d, %d, %d, %f)", rgba.R, rgba.G, rgba.B, rgba.A)
|
||
|
}
|
||
|
|
||
|
type Gradient struct {
|
||
|
Angle int
|
||
|
Colors []Color
|
||
|
}
|
||
|
|
||
|
func NewGradient(angle int, colors ...Color) Gradient {
|
||
|
return Gradient{angle, colors}
|
||
|
}
|
||
|
|
||
|
func (g Gradient) CSS() string {
|
||
|
var colors string
|
||
|
for i, color := range g.Colors {
|
||
|
if i != 0 {
|
||
|
colors += ", "
|
||
|
}
|
||
|
colors += color.CSS()
|
||
|
}
|
||
|
|
||
|
return fmt.Sprintf("linear-gradient(%ddeg, %s)", g.Angle, colors)
|
||
|
}
|