removed --sketch_bg and added --dark_theme option

This commit is contained in:
Vojtěch Fošnár 2023-01-09 22:16:22 +01:00
parent a81ab2d73e
commit a972b5b0ee
No known key found for this signature in database
GPG key ID: 657727E71C40859A
4 changed files with 81 additions and 474 deletions

View file

@ -27,6 +27,7 @@ import (
"oss.terrastruct.com/d2/d2renderers/d2latex" "oss.terrastruct.com/d2/d2renderers/d2latex"
"oss.terrastruct.com/d2/d2renderers/d2sketch" "oss.terrastruct.com/d2/d2renderers/d2sketch"
"oss.terrastruct.com/d2/d2target" "oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/d2themes/d2themescatalog"
"oss.terrastruct.com/d2/lib/color" "oss.terrastruct.com/d2/lib/color"
"oss.terrastruct.com/d2/lib/geo" "oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/label" "oss.terrastruct.com/d2/lib/label"
@ -53,7 +54,7 @@ var TooltipIcon string
var LinkIcon string var LinkIcon string
//go:embed style.css //go:embed style.css
var styleCSS string var baseStylesheet string
//go:embed sketchstyle.css //go:embed sketchstyle.css
var sketchStyleCSS string var sketchStyleCSS string
@ -62,10 +63,10 @@ var sketchStyleCSS string
var mdCSS string var mdCSS string
type RenderOpts struct { type RenderOpts struct {
Pad int Pad int
Sketch bool Sketch bool
SketchBg bool ThemeID int64
ThemeID int64 DarkThemeID int64
} }
func dimensions(writer io.Writer, diagram *d2target.Diagram, pad int) (width, height int, topLeft, bottomRight d2target.Point) { func dimensions(writer io.Writer, diagram *d2target.Diagram, pad int) (width, height int, topLeft, bottomRight d2target.Point) {
@ -1148,16 +1149,19 @@ var fitToScreenScript string
const ( const (
BG_COLOR = color.N7 BG_COLOR = color.N7
FG_COLOR = color.N1 FG_COLOR = color.N1
DEFAULT_THEME int64 = 0
DEFAULT_DARK_THEME int64 = math.MaxInt64 // no theme selected
) )
// TODO minify output at end // TODO minify output at end
func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) { func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
var sketchRunner *d2sketch.Runner var sketchRunner *d2sketch.Runner
pad := DEFAULT_PADDING pad := DEFAULT_PADDING
sketchBg := true themeID := DEFAULT_THEME
darkThemeID := DEFAULT_DARK_THEME
if opts != nil { if opts != nil {
pad = opts.Pad pad = opts.Pad
sketchBg = opts.SketchBg
if opts.Sketch { if opts.Sketch {
var err error var err error
sketchRunner, err = d2sketch.InitSketchVM() sketchRunner, err = d2sketch.InitSketchVM()
@ -1165,6 +1169,8 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
return nil, err return nil, err
} }
} }
themeID = opts.ThemeID
darkThemeID = opts.DarkThemeID
} }
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
@ -1245,11 +1251,12 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
// containerEl.Color = color.N1 TODO this is useless as this element has no children // containerEl.Color = color.N1 TODO this is useless as this element has no children
// generate elements that will be appended to the SVG tag // generate elements that will be appended to the SVG tag
styleCSS2 := "" themeStylesheet := themeCSS(themeID, darkThemeID)
sketchStylesheet := ""
if sketchRunner != nil { if sketchRunner != nil {
styleCSS2 = "\n" + sketchStyleCSS sketchStylesheet = "\n" + sketchStyleCSS
} }
svgOut := fmt.Sprintf(`<style type="text/css"><![CDATA[%s%s]]></style>`, styleCSS, styleCSS2) svgOut := fmt.Sprintf(`<style type="text/css"><![CDATA[%s%s%s]]></style>`, baseStylesheet, themeStylesheet, sketchStylesheet)
// 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)
@ -1263,7 +1270,7 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
if hasMarkdown { if hasMarkdown {
svgOut += fmt.Sprintf(`<style type="text/css">%s</style>`, mdCSS) svgOut += fmt.Sprintf(`<style type="text/css">%s</style>`, mdCSS)
} }
if sketchRunner != nil && sketchBg { if sketchRunner != nil {
svgOut += d2sketch.DefineFillPattern() svgOut += d2sketch.DefineFillPattern()
} }
svgOut += embedFonts(buf, diagram.FontFamily) svgOut += embedFonts(buf, diagram.FontFamily)
@ -1278,6 +1285,44 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
return []byte(docRendered), nil return []byte(docRendered), nil
} }
func themeCSS(themeID, darkThemeID int64) (stylesheet string) {
out := singleThemeRulesets(themeID)
if darkThemeID != math.MaxInt64 {
out += fmt.Sprintf("@media screen and (prefers-color-scheme:dark){%s}", singleThemeRulesets(darkThemeID))
}
return out
}
func singleThemeRulesets(themeID int64) (rulesets string) {
out := ""
theme := d2themescatalog.Find(themeID)
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;}",
property, property, theme.Colors.Neutrals.N1,
property, property, theme.Colors.Neutrals.N2,
property, property, theme.Colors.Neutrals.N3,
property, property, theme.Colors.Neutrals.N4,
property, property, theme.Colors.Neutrals.N5,
property, property, theme.Colors.Neutrals.N6,
property, property, theme.Colors.Neutrals.N7,
property, property, theme.Colors.B1,
property, property, theme.Colors.B2,
property, property, theme.Colors.B3,
property, property, theme.Colors.B4,
property, property, theme.Colors.B5,
property, property, theme.Colors.B6,
property, property, theme.Colors.AA2,
property, property, theme.Colors.AA4,
property, property, theme.Colors.AA5,
property, property, theme.Colors.AB4,
property, property, theme.Colors.AB5,
)
}
return out
}
type DiagramObject interface { type DiagramObject interface {
GetID() string GetID() string
GetZIndex() int GetZIndex() int

View file

@ -10,453 +10,3 @@
mix-Blend-mode: multiply; mix-Blend-mode: multiply;
opacity: 0.5; opacity: 0.5;
} }
/*
.fill
.stroke
.background-color
.color
*/
.fill-N1 {
fill: #0A0F25;
}
.fill-N2 {
fill: #676C7E;
}
.fill-N3 {
fill: #9499AB;
}
.fill-N4 {
fill: #CFD2DD;
}
.fill-N5 {
fill: #DEE1EB;
}
.fill-N6 {
fill: #EEF1F8;
}
.fill-N7 {
fill: #FFFFFF;
}
.fill-B1 {
fill: #0D32B2;
}
.fill-B2 {
fill: #0D32B2;
}
.fill-B3 {
fill: #E3E9FD;
}
.fill-B4 {
fill: #E3E9FD;
}
.fill-B5 {
fill: #EDF0FD;
}
.fill-B6 {
fill: #F7F8FE;
}
.fill-AA2 {
fill: #4A6FF3;
}
.fill-AA4 {
fill: #EDF0FD;
}
.fill-AA5 {
fill: #F7F8FE;
}
.fill-AB4 {
fill: #DEE1EB;
}
.fill-AB5 {
fill: #F7F8FE;
}
.stroke-N1 {
stroke: #0A0F25;
}
.stroke-N2 {
stroke: #676C7E;
}
.stroke-N3 {
stroke: #9499AB;
}
.stroke-N4 {
stroke: #CFD2DD;
}
.stroke-N5 {
stroke: #DEE1EB;
}
.stroke-N6 {
stroke: #EEF1F8;
}
.stroke-N7 {
stroke: #FFFFFF;
}
.stroke-B1 {
stroke: #0D32B2;
}
.stroke-B2 {
stroke: #0D32B2;
}
.stroke-B3 {
stroke: #E3E9FD;
}
.stroke-B4 {
stroke: #E3E9FD;
}
.stroke-B5 {
stroke: #EDF0FD;
}
.stroke-B6 {
stroke: #F7F8FE;
}
.stroke-AA2 {
stroke: #4A6FF3;
}
.stroke-AA4 {
stroke: #EDF0FD;
}
.stroke-AA5 {
stroke: #F7F8FE;
}
.stroke-AB4 {
stroke: #DEE1EB;
}
.stroke-AB5 {
stroke: #F7F8FE;
}
.background-color-N1 {
background-color: #0A0F25;
}
.background-color-N2 {
background-color: #676C7E;
}
.background-color-N3 {
background-color: #9499AB;
}
.background-color-N4 {
background-color: #CFD2DD;
}
.background-color-N5 {
background-color: #DEE1EB;
}
.background-color-N6 {
background-color: #EEF1F8;
}
.background-color-N7 {
background-color: #FFFFFF;
}
.background-color-B1 {
background-color: #0D32B2;
}
.background-color-B2 {
background-color: #0D32B2;
}
.background-color-B3 {
background-color: #E3E9FD;
}
.background-color-B4 {
background-color: #E3E9FD;
}
.background-color-B5 {
background-color: #EDF0FD;
}
.background-color-B6 {
background-color: #F7F8FE;
}
.background-color-AA2 {
background-color: #4A6FF3;
}
.background-color-AA4 {
background-color: #EDF0FD;
}
.background-color-AA5 {
background-color: #F7F8FE;
}
.background-color-AB4 {
background-color: #DEE1EB;
}
.background-color-AB5 {
background-color: #F7F8FE;
}
.color-N1 {
color: #0A0F25;
}
.color-N2 {
color: #676C7E;
}
.color-N3 {
color: #9499AB;
}
.color-N4 {
color: #CFD2DD;
}
.color-N5 {
color: #DEE1EB;
}
.color-N6 {
color: #EEF1F8;
}
.color-N7 {
color: #FFFFFF;
}
.color-B1 {
color: #0D32B2;
}
.color-B2 {
color: #0D32B2;
}
.color-B3 {
color: #E3E9FD;
}
.color-B4 {
color: #E3E9FD;
}
.color-B5 {
color: #EDF0FD;
}
.color-B6 {
color: #F7F8FE;
}
.color-AA2 {
color: #4A6FF3;
}
.color-AA4 {
color: #EDF0FD;
}
.color-AA5 {
color: #F7F8FE;
}
.color-AB4 {
color: #DEE1EB;
}
.color-AB5 {
color: #F7F8FE;
}
@media screen and (prefers-color-scheme: dark) {
.fill-N1 {
fill: #cdd6f4;
}
.fill-N2 {
fill: #bac2de;
}
.fill-N3 {
fill: #a6adc8;
}
.fill-N4 {
fill: #585b70;
}
.fill-N5 {
fill: #45475a;
}
.fill-N6 {
fill: #313244;
}
.fill-N7 {
fill: #1e1e2e;
}
.fill-B1 {
fill: #cba6f7;
}
.fill-B2 {
fill: #cba6f7;
}
.fill-B3 {
fill: #6c7086;
}
.fill-B4 {
fill: #585b70;
}
.fill-B5 {
fill: #45475a;
}
.fill-B6 {
fill: #313244;
}
.fill-AA2 {
fill: #f38ba8;
}
.fill-AA4 {
fill: #45475a;
}
.fill-AA5 {
fill: #313244;
}
.fill-AB4 {
fill: #45475a;
}
.fill-AB5 {
fill: #313244;
}
.stroke-N1 {
stroke: #cdd6f4;
}
.stroke-N2 {
stroke: #bac2de;
}
.stroke-N3 {
stroke: #a6adc8;
}
.stroke-N4 {
stroke: #585b70;
}
.stroke-N5 {
stroke: #45475a;
}
.stroke-N6 {
stroke: #313244;
}
.stroke-N7 {
stroke: #1e1e2e;
}
.stroke-B1 {
stroke: #cba6f7;
}
.stroke-B2 {
stroke: #cba6f7;
}
.stroke-B3 {
stroke: #6c7086;
}
.stroke-B4 {
stroke: #585b70;
}
.stroke-B5 {
stroke: #45475a;
}
.stroke-B6 {
stroke: #313244;
}
.stroke-AA2 {
stroke: #f38ba8;
}
.stroke-AA4 {
stroke: #45475a;
}
.stroke-AA5 {
stroke: #313244;
}
.stroke-AB4 {
stroke: #45475a;
}
.stroke-AB5 {
stroke: #313244;
}
.background-color-N1 {
background-color: #cdd6f4;
}
.background-color-N2 {
background-color: #bac2de;
}
.background-color-N3 {
background-color: #a6adc8;
}
.background-color-N4 {
background-color: #585b70;
}
.background-color-N5 {
background-color: #45475a;
}
.background-color-N6 {
background-color: #313244;
}
.background-color-N7 {
background-color: #1e1e2e;
}
.background-color-B1 {
background-color: #cba6f7;
}
.background-color-B2 {
background-color: #cba6f7;
}
.background-color-B3 {
background-color: #6c7086;
}
.background-color-B4 {
background-color: #585b70;
}
.background-color-B5 {
background-color: #45475a;
}
.background-color-B6 {
background-color: #313244;
}
.background-color-AA2 {
background-color: #f38ba8;
}
.background-color-AA4 {
background-color: #45475a;
}
.background-color-AA5 {
background-color: #313244;
}
.background-color-AB4 {
background-color: #45475a;
}
.background-color-AB5 {
background-color: #313244;
}
.color-N1 {
color: #cdd6f4;
}
.color-N2 {
color: #bac2de;
}
.color-N3 {
color: #a6adc8;
}
.color-N4 {
color: #585b70;
}
.color-N5 {
color: #45475a;
}
.color-N6 {
color: #313244;
}
.color-N7 {
color: #1e1e2e;
}
.color-B1 {
color: #cba6f7;
}
.color-B2 {
color: #cba6f7;
}
.color-B3 {
color: #6c7086;
}
.color-B4 {
color: #585b70;
}
.color-B5 {
color: #45475a;
}
.color-B6 {
color: #313244;
}
.color-AA2 {
color: #f38ba8;
}
.color-AA4 {
color: #45475a;
}
.color-AA5 {
color: #313244;
}
.color-AB4 {
color: #45475a;
}
.color-AB5 {
color: #313244;
}
}

34
main.go
View file

@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"math"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
@ -62,6 +63,10 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
if err != nil { if err != nil {
return err return err
} }
darkThemeFlag, err := ms.Opts.Int64("D2_D_THEME", "dark_theme", "", math.MaxInt64, "the diagram dark theme ID. When left unset only the theme will be applied")
if err != nil {
return err
}
padFlag, err := ms.Opts.Int64("D2_PAD", "pad", "", d2svg.DEFAULT_PADDING, "pixels padded around the rendered diagram") padFlag, err := ms.Opts.Int64("D2_PAD", "pad", "", d2svg.DEFAULT_PADDING, "pixels padded around the rendered diagram")
if err != nil { if err != nil {
return err return err
@ -75,11 +80,6 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
return err return err
} }
sketchBgFlag, err := ms.Opts.Bool("D2_SKT_BG", "sketch_bg", "", true, "make the background look like it was sketched too")
if err != nil {
return err
}
ps, err := d2plugin.ListPlugins(ctx) ps, err := d2plugin.ListPlugins(ctx)
if err != nil { if err != nil {
return err return err
@ -151,6 +151,14 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
} }
ms.Log.Debug.Printf("using theme %s (ID: %d)", match.Name, *themeFlag) ms.Log.Debug.Printf("using theme %s (ID: %d)", match.Name, *themeFlag)
if *darkThemeFlag != math.MaxInt64 {
match = d2themescatalog.Find(*darkThemeFlag)
if match == (d2themes.Theme{}) {
return xmain.UsageErrorf("--dark_theme could not be found. The available options are:\n%s\nYou provided: %d", d2themescatalog.CLIString(), *darkThemeFlag)
}
ms.Log.Debug.Printf("using dark theme %s (ID: %d)", match.Name, *darkThemeFlag)
}
plugin, err := d2plugin.FindPlugin(ctx, ps, *layoutFlag) plugin, err := d2plugin.FindPlugin(ctx, ps, *layoutFlag)
if err != nil { if err != nil {
if errors.Is(err, exec.ErrNotFound) { if errors.Is(err, exec.ErrNotFound) {
@ -176,6 +184,9 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
var pw png.Playwright var pw png.Playwright
if filepath.Ext(outputPath) == ".png" { if filepath.Ext(outputPath) == ".png" {
if *darkThemeFlag != math.MaxInt64 {
return xmain.UsageErrorf("--dark_theme cannot be used while exporting to another format other than .svg")
}
pw, err = png.InitPlaywright() pw, err = png.InitPlaywright()
if err != nil { if err != nil {
return err return err
@ -197,6 +208,7 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
layoutPlugin: plugin, layoutPlugin: plugin,
sketch: *sketchFlag, sketch: *sketchFlag,
themeID: *themeFlag, themeID: *themeFlag,
darkThemeID: *darkThemeFlag,
pad: *padFlag, pad: *padFlag,
host: *hostFlag, host: *hostFlag,
port: *portFlag, port: *portFlag,
@ -214,7 +226,7 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
ctx, cancel := context.WithTimeout(ctx, time.Minute*2) ctx, cancel := context.WithTimeout(ctx, time.Minute*2)
defer cancel() defer cancel()
_, written, err := compile(ctx, ms, plugin, *sketchFlag, *sketchBgFlag, *padFlag, *themeFlag, inputPath, outputPath, *bundleFlag, pw.Page) _, written, err := compile(ctx, ms, plugin, *sketchFlag, *padFlag, *themeFlag, *darkThemeFlag, inputPath, outputPath, *bundleFlag, pw.Page)
if err != nil { if err != nil {
if written { if written {
return fmt.Errorf("failed to fully compile (partial render written): %w", err) return fmt.Errorf("failed to fully compile (partial render written): %w", err)
@ -225,7 +237,7 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
return nil return nil
} }
func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, sketch bool, sketchBg bool, pad, themeID int64, inputPath, outputPath string, bundle bool, page playwright.Page) (_ []byte, written bool, _ error) { func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, sketch bool, pad, themeID, themeDarkID int64, inputPath, outputPath string, bundle bool, page playwright.Page) (_ []byte, written bool, _ error) {
input, err := ms.ReadPath(inputPath) input, err := ms.ReadPath(inputPath)
if err != nil { if err != nil {
return nil, false, err return nil, false, err
@ -250,10 +262,10 @@ func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, sketc
} }
svg, err := d2svg.Render(diagram, &d2svg.RenderOpts{ svg, err := d2svg.Render(diagram, &d2svg.RenderOpts{
Pad: int(pad), Pad: int(pad),
Sketch: sketch, Sketch: sketch,
SketchBg: sketchBg, ThemeID: themeID,
ThemeID: themeID, DarkThemeID: themeDarkID,
}) })
if err != nil { if err != nil {
return nil, false, err return nil, false, err

View file

@ -41,9 +41,9 @@ var staticFS embed.FS
type watcherOpts struct { type watcherOpts struct {
layoutPlugin d2plugin.Plugin layoutPlugin d2plugin.Plugin
themeID int64 themeID int64
darkThemeID int64
pad int64 pad int64
sketch bool sketch bool
sketchBg bool
host string host string
port string port string
inputPath string inputPath string
@ -357,7 +357,7 @@ func (w *watcher) compileLoop(ctx context.Context) error {
w.pw = newPW w.pw = newPW
} }
svg, _, err := compile(ctx, w.ms, w.layoutPlugin, w.sketch, w.sketchBg, w.pad, w.themeID, w.inputPath, w.outputPath, w.bundle, w.pw.Page) svg, _, err := compile(ctx, w.ms, w.layoutPlugin, w.sketch, w.pad, w.themeID, w.darkThemeID, w.inputPath, w.outputPath, w.bundle, w.pw.Page)
errs := "" errs := ""
if err != nil { if err != nil {
if len(svg) > 0 { if len(svg) > 0 {