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/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"
@ -53,7 +54,7 @@ var TooltipIcon string
var LinkIcon string
//go:embed style.css
var styleCSS string
var baseStylesheet string
//go:embed sketchstyle.css
var sketchStyleCSS string
@ -62,10 +63,10 @@ var sketchStyleCSS string
var mdCSS string
type RenderOpts struct {
Pad int
Sketch bool
SketchBg bool
ThemeID int64
Pad int
Sketch bool
ThemeID int64
DarkThemeID int64
}
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 (
BG_COLOR = color.N7
FG_COLOR = color.N1
DEFAULT_THEME int64 = 0
DEFAULT_DARK_THEME int64 = math.MaxInt64 // no theme selected
)
// TODO minify output at end
func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
var sketchRunner *d2sketch.Runner
pad := DEFAULT_PADDING
sketchBg := true
themeID := DEFAULT_THEME
darkThemeID := DEFAULT_DARK_THEME
if opts != nil {
pad = opts.Pad
sketchBg = opts.SketchBg
if opts.Sketch {
var err error
sketchRunner, err = d2sketch.InitSketchVM()
@ -1165,6 +1169,8 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
return nil, err
}
}
themeID = opts.ThemeID
darkThemeID = opts.DarkThemeID
}
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
// generate elements that will be appended to the SVG tag
styleCSS2 := ""
themeStylesheet := themeCSS(themeID, darkThemeID)
sketchStylesheet := ""
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
// https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
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 {
svgOut += fmt.Sprintf(`<style type="text/css">%s</style>`, mdCSS)
}
if sketchRunner != nil && sketchBg {
if sketchRunner != nil {
svgOut += d2sketch.DefineFillPattern()
}
svgOut += embedFonts(buf, diagram.FontFamily)
@ -1278,6 +1285,44 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
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 {
GetID() string
GetZIndex() int

View file

@ -10,453 +10,3 @@
mix-Blend-mode: multiply;
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"
"fmt"
"io"
"math"
"os/exec"
"path/filepath"
"strings"
@ -62,6 +63,10 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
if err != nil {
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")
if err != nil {
return err
@ -75,11 +80,6 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
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)
if err != nil {
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)
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)
if err != nil {
if errors.Is(err, exec.ErrNotFound) {
@ -176,6 +184,9 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
var pw png.Playwright
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()
if err != nil {
return err
@ -197,6 +208,7 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
layoutPlugin: plugin,
sketch: *sketchFlag,
themeID: *themeFlag,
darkThemeID: *darkThemeFlag,
pad: *padFlag,
host: *hostFlag,
port: *portFlag,
@ -214,7 +226,7 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
ctx, cancel := context.WithTimeout(ctx, time.Minute*2)
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 written {
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
}
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)
if err != nil {
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{
Pad: int(pad),
Sketch: sketch,
SketchBg: sketchBg,
ThemeID: themeID,
Pad: int(pad),
Sketch: sketch,
ThemeID: themeID,
DarkThemeID: themeDarkID,
})
if err != nil {
return nil, false, err

View file

@ -41,9 +41,9 @@ var staticFS embed.FS
type watcherOpts struct {
layoutPlugin d2plugin.Plugin
themeID int64
darkThemeID int64
pad int64
sketch bool
sketchBg bool
host string
port string
inputPath string
@ -357,7 +357,7 @@ func (w *watcher) compileLoop(ctx context.Context) error {
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 := ""
if err != nil {
if len(svg) > 0 {