vary sketch overlay color depending on the background and small refactoring
This commit is contained in:
parent
fb6eee9a24
commit
63a0c1e2b1
9 changed files with 328 additions and 111 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -56,9 +56,6 @@ var LinkIcon string
|
||||||
//go:embed style.css
|
//go:embed style.css
|
||||||
var baseStylesheet string
|
var baseStylesheet string
|
||||||
|
|
||||||
//go:embed sketchstyle.css
|
|
||||||
var sketchStyleCSS string
|
|
||||||
|
|
||||||
//go:embed github-markdown.css
|
//go:embed github-markdown.css
|
||||||
var mdCSS string
|
var mdCSS string
|
||||||
|
|
||||||
|
|
@ -1248,12 +1245,11 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
|
||||||
backgroundEl.Fill = color.N7
|
backgroundEl.Fill = color.N7
|
||||||
|
|
||||||
// generate elements that will be appended to the SVG tag
|
// generate elements that will be appended to the SVG tag
|
||||||
themeStylesheet := themeCSS(themeID, darkThemeID)
|
themeStylesheet, err := themeCSS(themeID, darkThemeID)
|
||||||
sketchStylesheet := ""
|
if err != nil {
|
||||||
if sketchRunner != nil {
|
return nil, err
|
||||||
sketchStylesheet = "\n" + sketchStyleCSS
|
|
||||||
}
|
}
|
||||||
svgOut := fmt.Sprintf(`<style type="text/css"><![CDATA[%s%s%s]]></style>`, baseStylesheet, themeStylesheet, sketchStylesheet)
|
svgOut := fmt.Sprintf(`<style type="text/css"><![CDATA[%s%s]]></style>`, baseStylesheet, themeStylesheet)
|
||||||
// this script won't run in --watch mode because script tags are ignored when added via el.innerHTML = element
|
// this script won't run in --watch mode because script tags are ignored when added via el.innerHTML = element
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
|
// https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
|
||||||
svgOut += fmt.Sprintf(`<script type="application/javascript"><![CDATA[%s]]></script>`, fitToScreenScript)
|
svgOut += fmt.Sprintf(`<script type="application/javascript"><![CDATA[%s]]></script>`, fitToScreenScript)
|
||||||
|
|
@ -1268,7 +1264,7 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
|
||||||
svgOut += fmt.Sprintf(`<style type="text/css">%s</style>`, mdCSS)
|
svgOut += fmt.Sprintf(`<style type="text/css">%s</style>`, mdCSS)
|
||||||
}
|
}
|
||||||
if sketchRunner != nil {
|
if sketchRunner != nil {
|
||||||
svgOut += d2sketch.DefineFillPattern()
|
svgOut += d2sketch.DefineFillPatterns()
|
||||||
}
|
}
|
||||||
svgOut += embedFonts(buf, diagram.FontFamily)
|
svgOut += embedFonts(buf, diagram.FontFamily)
|
||||||
|
|
||||||
|
|
@ -1282,20 +1278,29 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
|
||||||
return []byte(docRendered), nil
|
return []byte(docRendered), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func themeCSS(themeID, darkThemeID int64) (stylesheet string) {
|
// TODO include only colors that are being used to reduce size
|
||||||
out := singleThemeRulesets(themeID)
|
func themeCSS(themeID, darkThemeID int64) (stylesheet string, err error) {
|
||||||
|
out, err := singleThemeRulesets(themeID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
if darkThemeID != math.MaxInt64 {
|
if darkThemeID != math.MaxInt64 {
|
||||||
out += fmt.Sprintf("@media screen and (prefers-color-scheme:dark){%s}", singleThemeRulesets(darkThemeID))
|
darkOut, err := singleThemeRulesets(darkThemeID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf("@media screen and (prefers-color-scheme:dark){%s}", darkOut)
|
||||||
}
|
}
|
||||||
|
|
||||||
return out
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func singleThemeRulesets(themeID int64) (rulesets string) {
|
func singleThemeRulesets(themeID int64) (rulesets string, err error) {
|
||||||
out := ""
|
out := ""
|
||||||
theme := d2themescatalog.Find(themeID)
|
theme := d2themescatalog.Find(themeID)
|
||||||
|
|
||||||
|
// Global theme colors
|
||||||
for _, property := range []string{"fill", "stroke", "background-color", "color"} {
|
for _, property := range []string{"fill", "stroke", "background-color", "color"} {
|
||||||
out += fmt.Sprintf(".%s-N1{%s:%s;}.%s-N2{%s:%s;}.%s-N3{%s:%s;}.%s-N4{%s:%s;}.%s-N5{%s:%s;}.%s-N6{%s:%s;}.%s-N7{%s:%s;}.%s-B1{%s:%s;}.%s-B2{%s:%s;}.%s-B3{%s:%s;}.%s-B4{%s:%s;}.%s-B5{%s:%s;}.%s-B6{%s:%s;}.%s-AA2{%s:%s;}.%s-AA4{%s:%s;}.%s-AA5{%s:%s;}.%s-AB4{%s:%s;}.%s-AB5{%s:%s;}",
|
out += fmt.Sprintf(".%s-N1{%s:%s;}.%s-N2{%s:%s;}.%s-N3{%s:%s;}.%s-N4{%s:%s;}.%s-N5{%s:%s;}.%s-N6{%s:%s;}.%s-N7{%s:%s;}.%s-B1{%s:%s;}.%s-B2{%s:%s;}.%s-B3{%s:%s;}.%s-B4{%s:%s;}.%s-B5{%s:%s;}.%s-B6{%s:%s;}.%s-AA2{%s:%s;}.%s-AA4{%s:%s;}.%s-AA5{%s:%s;}.%s-AB4{%s:%s;}.%s-AB5{%s:%s;}",
|
||||||
property, property, theme.Colors.Neutrals.N1,
|
property, property, theme.Colors.Neutrals.N1,
|
||||||
|
|
@ -1319,6 +1324,7 @@ func singleThemeRulesets(themeID int64) (rulesets string) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Markdown specific rulesets
|
||||||
out += fmt.Sprintf(".md{--color-fg-default:%s;--color-fg-muted:%s;--color-fg-subtle:%s;--color-canvas-default:%s;--color-canvas-subtle:%s;--color-border-default:%s;--color-border-muted:%s;--color-neutral-muted:%s;--color-accent-fg:%s;--color-accent-emphasis:%s;--color-attention-subtle:%s;--color-danger-fg:%s;}",
|
out += fmt.Sprintf(".md{--color-fg-default:%s;--color-fg-muted:%s;--color-fg-subtle:%s;--color-canvas-default:%s;--color-canvas-subtle:%s;--color-border-default:%s;--color-border-muted:%s;--color-neutral-muted:%s;--color-accent-fg:%s;--color-accent-emphasis:%s;--color-attention-subtle:%s;--color-danger-fg:%s;}",
|
||||||
theme.Colors.Neutrals.N1, theme.Colors.Neutrals.N2, theme.Colors.Neutrals.N3,
|
theme.Colors.Neutrals.N1, theme.Colors.Neutrals.N2, theme.Colors.Neutrals.N3,
|
||||||
theme.Colors.Neutrals.N7, theme.Colors.Neutrals.N6,
|
theme.Colors.Neutrals.N7, theme.Colors.Neutrals.N6,
|
||||||
|
|
@ -1329,7 +1335,91 @@ func singleThemeRulesets(themeID int64) (rulesets string) {
|
||||||
"red",
|
"red",
|
||||||
)
|
)
|
||||||
|
|
||||||
return out
|
// Sketch style specific rulesets
|
||||||
|
lc, err := color.LuminanceCategory(theme.Colors.B1)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf(".sketch-overlay-%s{fill:url(#streaks-%s);mix-blend-mode:%s}", color.B1, lc, blendMode(lc))
|
||||||
|
lc, err = color.LuminanceCategory(theme.Colors.B2)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf(".sketch-overlay-%s{fill:url(#streaks-%s);mix-blend-mode:%s}", color.B2, lc, blendMode(lc))
|
||||||
|
lc, err = color.LuminanceCategory(theme.Colors.B3)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf(".sketch-overlay-%s{fill:url(#streaks-%s);mix-blend-mode:%s}", color.B3, lc, blendMode(lc))
|
||||||
|
lc, err = color.LuminanceCategory(theme.Colors.B4)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf(".sketch-overlay-%s{fill:url(#streaks-%s);mix-blend-mode:%s}", color.B4, lc, blendMode(lc))
|
||||||
|
lc, err = color.LuminanceCategory(theme.Colors.B5)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf(".sketch-overlay-%s{fill:url(#streaks-%s);mix-blend-mode:%s}", color.B5, lc, blendMode(lc))
|
||||||
|
lc, err = color.LuminanceCategory(theme.Colors.B6)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf(".sketch-overlay-%s{fill:url(#streaks-%s);mix-blend-mode:%s}", color.B6, lc, blendMode(lc))
|
||||||
|
|
||||||
|
lc, err = color.LuminanceCategory(theme.Colors.Neutrals.N1)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf(".sketch-overlay-%s{fill:url(#streaks-%s);mix-blend-mode:%s}", color.N1, lc, blendMode(lc))
|
||||||
|
lc, err = color.LuminanceCategory(theme.Colors.Neutrals.N2)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf(".sketch-overlay-%s{fill:url(#streaks-%s);mix-blend-mode:%s}", color.N2, lc, blendMode(lc))
|
||||||
|
lc, err = color.LuminanceCategory(theme.Colors.Neutrals.N3)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf(".sketch-overlay-%s{fill:url(#streaks-%s);mix-blend-mode:%s}", color.N3, lc, blendMode(lc))
|
||||||
|
lc, err = color.LuminanceCategory(theme.Colors.Neutrals.N4)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf(".sketch-overlay-%s{fill:url(#streaks-%s);mix-blend-mode:%s}", color.N4, lc, blendMode(lc))
|
||||||
|
lc, err = color.LuminanceCategory(theme.Colors.Neutrals.N5)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf(".sketch-overlay-%s{fill:url(#streaks-%s);mix-blend-mode:%s}", color.N5, lc, blendMode(lc))
|
||||||
|
lc, err = color.LuminanceCategory(theme.Colors.Neutrals.N6)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf(".sketch-overlay-%s{fill:url(#streaks-%s);mix-blend-mode:%s}", color.N6, lc, blendMode(lc))
|
||||||
|
lc, err = color.LuminanceCategory(theme.Colors.Neutrals.N7)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
out += fmt.Sprintf(".sketch-overlay-%s{fill:url(#streaks-%s);mix-blend-mode:%s}", color.N7, lc, blendMode(lc))
|
||||||
|
|
||||||
|
// TODO Add the rest of the colors so we can allow the user to specify theme colors too
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func blendMode(lc string) string {
|
||||||
|
switch lc {
|
||||||
|
case "bright":
|
||||||
|
return "darken"
|
||||||
|
case "normal":
|
||||||
|
return "color-burn"
|
||||||
|
case "dark":
|
||||||
|
return "overlay"
|
||||||
|
case "darker":
|
||||||
|
return "lighten"
|
||||||
|
}
|
||||||
|
panic("invalid luminance category")
|
||||||
}
|
}
|
||||||
|
|
||||||
type DiagramObject interface {
|
type DiagramObject interface {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
.sketch-overlay {
|
|
||||||
fill: url(#streaks);
|
|
||||||
mix-blend-mode: overlay;
|
|
||||||
}
|
|
||||||
|
|
@ -10,3 +10,20 @@
|
||||||
mix-Blend-mode: multiply;
|
mix-Blend-mode: multiply;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sketch-overlay-bright {
|
||||||
|
fill: url(#streaks-bright);
|
||||||
|
mix-blend-mode: darken;
|
||||||
|
}
|
||||||
|
.sketch-overlay-normal {
|
||||||
|
fill: url(#streaks-normal);
|
||||||
|
mix-blend-mode: color-burn;
|
||||||
|
}
|
||||||
|
.sketch-overlay-dark {
|
||||||
|
fill: url(#streaks-dark);
|
||||||
|
mix-blend-mode: overlay;
|
||||||
|
}
|
||||||
|
.sketch-overlay-darker {
|
||||||
|
fill: url(#streaks-darker);
|
||||||
|
mix-blend-mode: lighten;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,21 @@
|
||||||
package color
|
package color
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/lucasb-eyer/go-colorful"
|
"github.com/lucasb-eyer/go-colorful"
|
||||||
"github.com/mazznoer/csscolorparser"
|
"github.com/mazznoer/csscolorparser"
|
||||||
)
|
)
|
||||||
|
|
||||||
var themeRegex = regexp.MustCompile("^B[1-6]$")
|
var themeColorRegex = regexp.MustCompile(`^N[1-7]|B[1-6]|AA[245]|AB[45]$`)
|
||||||
|
|
||||||
|
func IsThemeColor(colorString string) bool {
|
||||||
|
return themeColorRegex.Match([]byte(colorString))
|
||||||
|
}
|
||||||
|
|
||||||
func Darken(colorString string) (string, error) {
|
func Darken(colorString string) (string, error) {
|
||||||
if themeRegex.MatchString(colorString) {
|
if IsThemeColor(colorString) {
|
||||||
switch colorString[1] {
|
switch colorString[1] {
|
||||||
case '1':
|
case '1':
|
||||||
return B1, nil
|
return B1, nil
|
||||||
|
|
@ -24,13 +29,15 @@ func Darken(colorString string) (string, error) {
|
||||||
return B4, nil
|
return B4, nil
|
||||||
case '6':
|
case '6':
|
||||||
return B5, nil
|
return B5, nil
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("darkening color \"%s\" is not yet supported", colorString) // TODO Add the rest of the colors so we can allow the user to specify theme colors too
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return DarkenCSS(colorString)
|
return darkenCSS(colorString)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DarkenCSS(colorString string) (string, error) {
|
func darkenCSS(colorString string) (string, error) {
|
||||||
c, err := csscolorparser.Parse(colorString)
|
c, err := csscolorparser.Parse(colorString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
@ -40,6 +47,38 @@ func DarkenCSS(colorString string) (string, error) {
|
||||||
return colorful.Hsl(h, s, l-.1).Clamped().Hex(), nil
|
return colorful.Hsl(h, s, l-.1).Clamped().Hex(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LuminanceCategory(colorString string) (string, error) {
|
||||||
|
l, err := Luminance(colorString)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case l >= .88:
|
||||||
|
return "bright", nil
|
||||||
|
case l >= .55:
|
||||||
|
return "normal", nil
|
||||||
|
case l >= .30:
|
||||||
|
return "dark", nil
|
||||||
|
default:
|
||||||
|
return "darker", nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Luminance(colorString string) (float64, error) {
|
||||||
|
c, err := csscolorparser.Parse(colorString)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
l := float64(
|
||||||
|
float64(0.299)*float64(c.R) +
|
||||||
|
float64(0.587)*float64(c.G) +
|
||||||
|
float64(0.114)*float64(c.B),
|
||||||
|
)
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
N1 = "N1"
|
N1 = "N1"
|
||||||
N2 = "N2"
|
N2 = "N2"
|
||||||
|
|
|
||||||
52
lib/svg/style/common.go
Normal file
52
lib/svg/style/common.go
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
package style
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"oss.terrastruct.com/d2/d2target"
|
||||||
|
"oss.terrastruct.com/d2/lib/svg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ShapeStyle(shape d2target.Shape) string {
|
||||||
|
out := ""
|
||||||
|
|
||||||
|
out += fmt.Sprintf(`opacity:%f;`, shape.Opacity)
|
||||||
|
out += fmt.Sprintf(`stroke-width:%d;`, shape.StrokeWidth)
|
||||||
|
if shape.StrokeDash != 0 {
|
||||||
|
dashSize, gapSize := svg.GetStrokeDashAttributes(float64(shape.StrokeWidth), shape.StrokeDash)
|
||||||
|
out += fmt.Sprintf(`stroke-dasharray:%f,%f;`, dashSize, gapSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func ShapeTheme(shape d2target.Shape) (fill, stroke string) {
|
||||||
|
if shape.Type == d2target.ShapeSQLTable || shape.Type == d2target.ShapeClass {
|
||||||
|
// Fill is used for header fill in these types
|
||||||
|
// This fill property is just background of rows
|
||||||
|
fill = shape.Stroke
|
||||||
|
// Stroke (border) of these shapes should match the header fill
|
||||||
|
stroke = shape.Fill
|
||||||
|
} else {
|
||||||
|
fill = shape.Fill
|
||||||
|
stroke = shape.Stroke
|
||||||
|
}
|
||||||
|
return fill, stroke
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConnectionStyle(connection d2target.Connection) string {
|
||||||
|
out := ""
|
||||||
|
|
||||||
|
out += fmt.Sprintf(`opacity:%f;`, connection.Opacity)
|
||||||
|
out += fmt.Sprintf(`stroke-width:%d;`, connection.StrokeWidth)
|
||||||
|
if connection.StrokeDash != 0 {
|
||||||
|
dashSize, gapSize := svg.GetStrokeDashAttributes(float64(connection.StrokeWidth), connection.StrokeDash)
|
||||||
|
out += fmt.Sprintf(`stroke-dasharray:%f,%f;`, dashSize, gapSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func ConnectionTheme(connection d2target.Connection) (stroke string) {
|
||||||
|
return connection.Stroke
|
||||||
|
}
|
||||||
|
|
@ -3,57 +3,10 @@ package style
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"oss.terrastruct.com/d2/d2target"
|
|
||||||
"oss.terrastruct.com/d2/lib/color"
|
"oss.terrastruct.com/d2/lib/color"
|
||||||
"oss.terrastruct.com/d2/lib/svg"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func ShapeStyle(shape d2target.Shape) string {
|
|
||||||
out := ""
|
|
||||||
|
|
||||||
out += fmt.Sprintf(`opacity:%f;`, shape.Opacity)
|
|
||||||
out += fmt.Sprintf(`stroke-width:%d;`, shape.StrokeWidth)
|
|
||||||
if shape.StrokeDash != 0 {
|
|
||||||
dashSize, gapSize := svg.GetStrokeDashAttributes(float64(shape.StrokeWidth), shape.StrokeDash)
|
|
||||||
out += fmt.Sprintf(`stroke-dasharray:%f,%f;`, dashSize, gapSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func ShapeTheme(shape d2target.Shape) (fill, stroke string) {
|
|
||||||
if shape.Type == d2target.ShapeSQLTable || shape.Type == d2target.ShapeClass {
|
|
||||||
// Fill is used for header fill in these types
|
|
||||||
// This fill property is just background of rows
|
|
||||||
fill = shape.Stroke
|
|
||||||
// Stroke (border) of these shapes should match the header fill
|
|
||||||
stroke = shape.Fill
|
|
||||||
} else {
|
|
||||||
fill = shape.Fill
|
|
||||||
stroke = shape.Stroke
|
|
||||||
}
|
|
||||||
return fill, stroke
|
|
||||||
}
|
|
||||||
|
|
||||||
func ConnectionStyle(connection d2target.Connection) string {
|
|
||||||
out := ""
|
|
||||||
|
|
||||||
out += fmt.Sprintf(`opacity:%f;`, connection.Opacity)
|
|
||||||
out += fmt.Sprintf(`stroke-width:%d;`, connection.StrokeWidth)
|
|
||||||
if connection.StrokeDash != 0 {
|
|
||||||
dashSize, gapSize := svg.GetStrokeDashAttributes(float64(connection.StrokeWidth), connection.StrokeDash)
|
|
||||||
out += fmt.Sprintf(`stroke-dasharray:%f,%f;`, dashSize, gapSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func ConnectionTheme(connection d2target.Connection) (stroke string) {
|
|
||||||
return connection.Stroke
|
|
||||||
}
|
|
||||||
|
|
||||||
// ThemableElement is a helper class for creating new XML elements.
|
// ThemableElement is a helper class for creating new XML elements.
|
||||||
// This should be preffered over formatting and must be used
|
// This should be preffered over formatting and must be used
|
||||||
// whenever Fill, Stroke, BackgroundColor or Color contains a color from a theme.
|
// whenever Fill, Stroke, BackgroundColor or Color contains a color from a theme.
|
||||||
|
|
@ -128,8 +81,6 @@ func NewThemableElement(tag string) *ThemableElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (el *ThemableElement) Render() string {
|
func (el *ThemableElement) Render() string {
|
||||||
re := regexp.MustCompile(`^N[1-7]|B[1-6]|AA[245]|AB[45]$`)
|
|
||||||
|
|
||||||
out := "<" + el.tag
|
out := "<" + el.tag
|
||||||
|
|
||||||
if el.X != math.MaxFloat64 {
|
if el.X != math.MaxFloat64 {
|
||||||
|
|
@ -195,22 +146,22 @@ func (el *ThemableElement) Render() string {
|
||||||
style := el.Style
|
style := el.Style
|
||||||
|
|
||||||
// Add class {property}-{theme color} if the color is from a theme, set the property otherwise
|
// Add class {property}-{theme color} if the color is from a theme, set the property otherwise
|
||||||
if re.MatchString(el.Stroke) {
|
if color.IsThemeColor(el.Stroke) {
|
||||||
class += fmt.Sprintf(" stroke-%s", el.Stroke)
|
class += fmt.Sprintf(" stroke-%s", el.Stroke)
|
||||||
} else if len(el.Stroke) > 0 {
|
} else if len(el.Stroke) > 0 {
|
||||||
out += fmt.Sprintf(` stroke="%s"`, el.Stroke)
|
out += fmt.Sprintf(` stroke="%s"`, el.Stroke)
|
||||||
}
|
}
|
||||||
if re.MatchString(el.Fill) {
|
if color.IsThemeColor(el.Fill) {
|
||||||
class += fmt.Sprintf(" fill-%s", el.Fill)
|
class += fmt.Sprintf(" fill-%s", el.Fill)
|
||||||
} else if len(el.Fill) > 0 {
|
} else if len(el.Fill) > 0 {
|
||||||
out += fmt.Sprintf(` fill="%s"`, el.Fill)
|
out += fmt.Sprintf(` fill="%s"`, el.Fill)
|
||||||
}
|
}
|
||||||
if re.MatchString(el.BackgroundColor) {
|
if color.IsThemeColor(el.BackgroundColor) {
|
||||||
class += fmt.Sprintf(" background-color-%s", el.BackgroundColor)
|
class += fmt.Sprintf(" background-color-%s", el.BackgroundColor)
|
||||||
} else if len(el.BackgroundColor) > 0 {
|
} else if len(el.BackgroundColor) > 0 {
|
||||||
out += fmt.Sprintf(` background-color="%s"`, el.BackgroundColor)
|
out += fmt.Sprintf(` background-color="%s"`, el.BackgroundColor)
|
||||||
}
|
}
|
||||||
if re.MatchString(el.Color) {
|
if color.IsThemeColor(el.Color) {
|
||||||
class += fmt.Sprintf(" color-%s", el.Color)
|
class += fmt.Sprintf(" color-%s", el.Color)
|
||||||
} else if len(el.Color) > 0 {
|
} else if len(el.Color) > 0 {
|
||||||
out += fmt.Sprintf(` color="%s"`, el.Color)
|
out += fmt.Sprintf(` color="%s"`, el.Color)
|
||||||
34
lib/svg/style/sketch_overlay.go
Normal file
34
lib/svg/style/sketch_overlay.go
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
package style
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"oss.terrastruct.com/d2/lib/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ThemableSketchOverlay struct {
|
||||||
|
el *ThemableElement
|
||||||
|
fill string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewThemableSketchOverlay(el *ThemableElement, fill string) *ThemableSketchOverlay {
|
||||||
|
return &ThemableSketchOverlay{
|
||||||
|
el,
|
||||||
|
fill,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WARNING: Do not reuse the element afterwards as this function changes the Class propery
|
||||||
|
func (o *ThemableSketchOverlay) Render() (string, error) {
|
||||||
|
if color.IsThemeColor(o.fill) {
|
||||||
|
o.el.Class += fmt.Sprintf(" sketch-overlay-%s", o.fill) // e.g. sketch-overlay-B3
|
||||||
|
} else {
|
||||||
|
lc, err := color.LuminanceCategory(o.fill)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
o.el.Class += fmt.Sprintf(" sketch-overlay-%s", lc) // e.g. sketch-overlay-dark
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.el.Render(), nil
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue