diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go index 678f0c2ae..cc0073184 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -27,6 +27,7 @@ import ( "oss.terrastruct.com/d2/d2renderers/d2latex" "oss.terrastruct.com/d2/d2renderers/d2sketch" "oss.terrastruct.com/d2/d2target" + "oss.terrastruct.com/d2/d2themes/d2themescatalog" "oss.terrastruct.com/d2/lib/color" "oss.terrastruct.com/d2/lib/geo" "oss.terrastruct.com/d2/lib/label" @@ -61,11 +62,12 @@ var sketchStyleCSS string var mdCSS string type RenderOpts struct { - Pad int - Sketch bool + Pad int + Sketch bool + ThemeID int64 } -func setViewbox(writer io.Writer, diagram *d2target.Diagram, pad int) (width int, height int) { +func setViewbox(writer io.Writer, diagram *d2target.Diagram, pad int, bgColor string) (width int, height int) { tl, br := diagram.BoundingBox() w := br.X - tl.X + pad*2 h := br.Y - tl.Y + pad*2 @@ -75,9 +77,9 @@ func setViewbox(writer io.Writer, diagram *d2target.Diagram, pad int) (width int fmt.Fprintf(writer, ` `, w, h, tl.X-pad, tl.Y-pad, w, h) +width="%d" height="%d" viewBox="%d %d %d %d">`, bgColor, w, h, tl.X-pad, tl.Y-pad, w, h) return w, h } @@ -123,7 +125,7 @@ func arrowheadDimensions(arrowhead d2target.Arrowhead, strokeWidth float64) (wid return clippedStrokeWidth * widthMultiplier, clippedStrokeWidth * heightMultiplier } -func arrowheadMarker(isTarget bool, id string, connection d2target.Connection) string { +func arrowheadMarker(isTarget bool, id string, bgColor string, connection d2target.Connection) string { arrowhead := connection.DstArrow if !isTarget { arrowhead = connection.SrcArrow @@ -206,7 +208,7 @@ func arrowheadMarker(isTarget bool, id string, connection d2target.Connection) s ) } case d2target.DiamondArrowhead: - attrs := fmt.Sprintf(`class="connection" fill="white" stroke="%s" stroke-width="%d"`, connection.Stroke, connection.StrokeWidth) + attrs := fmt.Sprintf(`class="connection" fill="%s" stroke="%s" stroke-width="%d"`, bgColor, connection.Stroke, connection.StrokeWidth) if isTarget { path = fmt.Sprintf(``, attrs, @@ -225,7 +227,7 @@ func arrowheadMarker(isTarget bool, id string, connection d2target.Connection) s ) } case d2target.CfOne, d2target.CfMany, d2target.CfOneRequired, d2target.CfManyRequired: - attrs := fmt.Sprintf(`class="connection" stroke="%s" stroke-width="%d" fill="white"`, connection.Stroke, connection.StrokeWidth) + attrs := fmt.Sprintf(`class="connection" stroke="%s" stroke-width="%d" fill="%s"`, connection.Stroke, connection.StrokeWidth, bgColor) offset := 4.0 + float64(connection.StrokeWidth*2) var modifier string if arrowhead == d2target.CfOneRequired || arrowhead == d2target.CfManyRequired { @@ -407,13 +409,13 @@ func makeLabelMask(labelTL *geo.Point, width, height int) string { ) } -func drawConnection(writer io.Writer, labelMaskID string, connection d2target.Connection, markers map[string]struct{}, idToShape map[string]d2target.Shape, sketchRunner *d2sketch.Runner) (labelMask string, _ error) { +func drawConnection(writer io.Writer, bgColor string, fgColor string, labelMaskID string, connection d2target.Connection, markers map[string]struct{}, idToShape map[string]d2target.Shape, sketchRunner *d2sketch.Runner) (labelMask string, _ error) { fmt.Fprintf(writer, ``, svg.EscapeText(connection.ID)) var markerStart string if connection.SrcArrow != d2target.NoArrowhead { id := arrowheadMarkerID(false, connection) if _, in := markers[id]; !in { - marker := arrowheadMarker(false, id, connection) + marker := arrowheadMarker(false, id, bgColor, connection) if marker == "" { panic(fmt.Sprintf("received empty arrow head marker for: %#v", connection)) } @@ -427,7 +429,7 @@ func drawConnection(writer io.Writer, labelMaskID string, connection d2target.Co if connection.DstArrow != d2target.NoArrowhead { id := arrowheadMarkerID(true, connection) if _, in := markers[id]; !in { - marker := arrowheadMarker(true, id, connection) + marker := arrowheadMarker(true, id, bgColor, connection) if marker == "" { panic(fmt.Sprintf("received empty arrow head marker for: %#v", connection)) } @@ -500,7 +502,7 @@ func drawConnection(writer io.Writer, labelMaskID string, connection d2target.Co if length > 0 { position = size / length } - fmt.Fprint(writer, renderArrowheadLabel(connection, connection.SrcLabel, position, size, size)) + fmt.Fprint(writer, renderArrowheadLabel(fgColor, connection, connection.SrcLabel, position, size, size)) } if connection.DstLabel != "" { // TODO use arrowhead label dimensions https://github.com/terrastruct/d2/issues/183 @@ -509,16 +511,16 @@ func drawConnection(writer io.Writer, labelMaskID string, connection d2target.Co if length > 0 { position -= size / length } - fmt.Fprint(writer, renderArrowheadLabel(connection, connection.DstLabel, position, size, size)) + fmt.Fprint(writer, renderArrowheadLabel(fgColor, connection, connection.DstLabel, position, size, size)) } fmt.Fprintf(writer, ``) return } -func renderArrowheadLabel(connection d2target.Connection, text string, position, width, height float64) string { +func renderArrowheadLabel(fgColor string, connection d2target.Connection, text string, position, width, height float64) string { labelTL := label.UnlockedTop.GetPointOnRoute(connection.Route, float64(connection.StrokeWidth), position, width, height) - textStyle := fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s", "middle", connection.FontSize, "black") + textStyle := fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s", "middle", connection.FontSize, fgColor) x := labelTL.X + width/2 y := labelTL.Y + float64(connection.FontSize) return fmt.Sprintf(`%s`, @@ -1115,8 +1117,12 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) { } } + theme := d2themescatalog.Find(opts.ThemeID) + bgColor := theme.Colors.Neutrals.N7 + fgColor := theme.Colors.Neutrals.N1 + buf := &bytes.Buffer{} - w, h := setViewbox(buf, diagram, pad) + w, h := setViewbox(buf, diagram, pad, bgColor) styleCSS2 := "" if sketchRunner != nil { @@ -1179,7 +1185,7 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) { markers := map[string]struct{}{} for _, obj := range allObjects { if c, is := obj.(d2target.Connection); is { - labelMask, err := drawConnection(buf, labelMaskID, c, markers, idToShape, sketchRunner) + labelMask, err := drawConnection(buf, bgColor, fgColor, labelMaskID, c, markers, idToShape, sketchRunner) if err != nil { return nil, err } diff --git a/d2themes/d2themes.go b/d2themes/d2themes.go index 3cd9f5830..71c16b239 100644 --- a/d2themes/d2themes.go +++ b/d2themes/d2themes.go @@ -58,3 +58,13 @@ var WarmNeutral = Neutral{ N6: "#ECEBEB", N7: "#FFFFFF", } + +var CattpuccinMochaNeutral = Neutral{ + N1: "#cdd6f4", + N2: "#bac2de", + N3: "#a6adc8", + N4: "#585b70", + N5: "#45475a", + N6: "#313244", + N7: "#1e1e2e", +} diff --git a/d2themes/d2themescatalog/catalog.go b/d2themes/d2themescatalog/catalog.go index 4e059029b..28ebcebdf 100644 --- a/d2themes/d2themescatalog/catalog.go +++ b/d2themes/d2themescatalog/catalog.go @@ -22,6 +22,7 @@ var Catalog = []d2themes.Theme{ EarthTones, EvergladeGreen, ButteredToast, + CatppuccinMochaMauve, } func Find(id int64) d2themes.Theme { diff --git a/d2themes/d2themescatalog/catppuccin_mocha_mauve.go b/d2themes/d2themescatalog/catppuccin_mocha_mauve.go new file mode 100644 index 000000000..bda242cae --- /dev/null +++ b/d2themes/d2themescatalog/catppuccin_mocha_mauve.go @@ -0,0 +1,25 @@ +package d2themescatalog + +import "oss.terrastruct.com/d2/d2themes" + +var CatppuccinMochaMauve = d2themes.Theme{ + ID: 200, + Name: "Catppuccin Mocha Mauve", + Colors: d2themes.ColorPalette{ + Neutrals: d2themes.CattpuccinMochaNeutral, + + B1: "#cba6f7", + B2: "#cba6f7", + B3: "#6c7086", + B4: "#585b70", + B5: "#45475a", + B6: "#313244", + + AA2: "#f38ba8", + AA4: "#45475a", + AA5: "#313244", + + AB4: "#45475a", + AB5: "#313244", + }, +} diff --git a/main.go b/main.go index 646b8c994..eacb717ff 100644 --- a/main.go +++ b/main.go @@ -248,6 +248,7 @@ func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, sketc svg, err := d2svg.Render(diagram, &d2svg.RenderOpts{ Pad: int(pad), Sketch: sketch, + ThemeID: themeID, }) if err != nil { return nil, false, err