Merge branch 'terrastruct:master' into master

This commit is contained in:
Alexander Wang 2023-02-23 10:13:16 -08:00 committed by GitHub
commit 2a05db0fd2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
619 changed files with 22070 additions and 21493 deletions

View file

@ -66,6 +66,9 @@ Port listening address when used with
.It Fl t , -theme Ar 0
Set the diagram theme ID
.Ns .
.It Fl -dark-theme Ar -1
the diagram dark theme ID. When left unset only the theme will be applied
.Ns .
.It Fl s , -sketch Ar false
Renders the diagram to look like it was sketched by hand
.Ns .

2
ci/sub

@ -1 +1 @@
Subproject commit 512bad5a958c5e33ba9b3e89dfac1bfd6002f98c
Subproject commit cb8a9993d7e1d91815650c5baade7658622189b9

View file

@ -128,7 +128,7 @@ func test(t *testing.T, textPath, text string) {
t.Fatal(err)
}
_, err = d2exporter.Export(ctx, g, 0, nil)
_, err = d2exporter.Export(ctx, g, nil)
if err != nil {
t.Fatal(err)
}

View file

@ -9,13 +9,10 @@ import (
"oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2renderers/d2fonts"
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/d2themes"
"oss.terrastruct.com/d2/d2themes/d2themescatalog"
"oss.terrastruct.com/d2/lib/color"
)
func Export(ctx context.Context, g *d2graph.Graph, themeID int64, fontFamily *d2fonts.FontFamily) (*d2target.Diagram, error) {
theme := d2themescatalog.Find(themeID)
func Export(ctx context.Context, g *d2graph.Graph, fontFamily *d2fonts.FontFamily) (*d2target.Diagram, error) {
diagram := d2target.NewDiagram()
diagram.Name = g.Name
if fontFamily == nil {
@ -25,27 +22,27 @@ func Export(ctx context.Context, g *d2graph.Graph, themeID int64, fontFamily *d2
diagram.Shapes = make([]d2target.Shape, len(g.Objects))
for i := range g.Objects {
diagram.Shapes[i] = toShape(g.Objects[i], &theme)
diagram.Shapes[i] = toShape(g.Objects[i])
}
diagram.Connections = make([]d2target.Connection, len(g.Edges))
for i := range g.Edges {
diagram.Connections[i] = toConnection(g.Edges[i], &theme)
diagram.Connections[i] = toConnection(g.Edges[i])
}
return diagram, nil
}
func applyTheme(shape *d2target.Shape, obj *d2graph.Object, theme *d2themes.Theme) {
shape.Stroke = obj.GetStroke(theme, shape.StrokeDash)
shape.Fill = obj.GetFill(theme)
func applyTheme(shape *d2target.Shape, obj *d2graph.Object) {
shape.Stroke = obj.GetStroke(shape.StrokeDash)
shape.Fill = obj.GetFill()
if obj.Attributes.Shape.Value == d2target.ShapeText {
shape.Color = theme.Colors.Neutrals.N1
shape.Color = color.N1
}
if obj.Attributes.Shape.Value == d2target.ShapeSQLTable || obj.Attributes.Shape.Value == d2target.ShapeClass {
shape.PrimaryAccentColor = theme.Colors.B2
shape.SecondaryAccentColor = theme.Colors.AA2
shape.NeutralAccentColor = theme.Colors.Neutrals.N2
shape.PrimaryAccentColor = color.B2
shape.SecondaryAccentColor = color.AA2
shape.NeutralAccentColor = color.N2
}
}
@ -100,7 +97,7 @@ func applyStyles(shape *d2target.Shape, obj *d2graph.Object) {
}
}
func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape {
func toShape(obj *d2graph.Object) d2target.Shape {
shape := d2target.BaseShape()
shape.SetType(obj.Attributes.Shape.Value)
shape.ID = obj.AbsID()
@ -125,8 +122,8 @@ func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape {
}
applyStyles(shape, obj)
applyTheme(shape, obj, theme)
shape.Color = text.GetColor(theme, shape.Italic)
applyTheme(shape, obj)
shape.Color = text.GetColor(shape.Italic)
applyStyles(shape, obj)
switch obj.Attributes.Shape.Value {
@ -166,7 +163,7 @@ func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape {
return *shape
}
func toConnection(edge *d2graph.Edge, theme *d2themes.Theme) d2target.Connection {
func toConnection(edge *d2graph.Edge) d2target.Connection {
connection := d2target.BaseConnection()
connection.ID = edge.AbsID()
connection.ZIndex = edge.ZIndex
@ -214,7 +211,7 @@ func toConnection(edge *d2graph.Edge, theme *d2themes.Theme) d2target.Connection
if edge.Attributes.Style.StrokeDash != nil {
connection.StrokeDash, _ = strconv.ParseFloat(edge.Attributes.Style.StrokeDash.Value, 64)
}
connection.Stroke = edge.GetStroke(theme, connection.StrokeDash)
connection.Stroke = edge.GetStroke(connection.StrokeDash)
if edge.Attributes.Style.Stroke != nil {
connection.Stroke = edge.Attributes.Style.Stroke.Value
}
@ -245,7 +242,7 @@ func toConnection(edge *d2graph.Edge, theme *d2themes.Theme) d2target.Connection
connection.Italic, _ = strconv.ParseBool(edge.Attributes.Style.Italic.Value)
}
connection.Color = text.GetColor(theme, connection.Italic)
connection.Color = text.GetColor(connection.Italic)
if edge.Attributes.Style.FontColor != nil {
connection.Color = edge.Attributes.Style.FontColor.Value
}

View file

@ -18,16 +18,14 @@ import (
"oss.terrastruct.com/d2/d2layouts/d2dagrelayout"
"oss.terrastruct.com/d2/d2layouts/d2sequence"
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/d2themes/d2themescatalog"
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/log"
"oss.terrastruct.com/d2/lib/textmeasure"
)
type testCase struct {
name string
dsl string
themeID int64
name string
dsl string
assertions func(t *testing.T, d *d2target.Diagram)
}
@ -132,8 +130,7 @@ func testConnection(t *testing.T) {
{
// This is a regression test where a connection with stroke-dash of 0 on terrastruct flagship theme would have a diff color
// than a connection without stroke dash
themeID: d2themescatalog.FlagshipTerrastruct.ID,
name: "theme_stroke-dash",
name: "theme_stroke-dash",
dsl: `x -> y: { style.stroke-dash: 0 }
x -> y
`,
@ -168,16 +165,14 @@ func testLabel(t *testing.T) {
func testTheme(t *testing.T) {
tcs := []testCase{
{
name: "shape_without_bold",
themeID: d2themescatalog.FlagshipTerrastruct.ID,
name: "shape_without_bold",
dsl: `x: {
style.bold: false
}
`,
},
{
name: "shape_with_italic",
themeID: d2themescatalog.FlagshipTerrastruct.ID,
name: "shape_with_italic",
dsl: `x: {
style.italic: true
}
@ -187,7 +182,6 @@ func testTheme(t *testing.T) {
name: "connection_without_italic",
dsl: `x -> y: asdf { style.italic: false }
`,
themeID: d2themescatalog.FlagshipTerrastruct.ID,
},
{
name: "connection_with_italic",
@ -195,7 +189,6 @@ func testTheme(t *testing.T) {
style.italic: true
}
`,
themeID: d2themescatalog.FlagshipTerrastruct.ID,
},
{
name: "connection_with_bold",
@ -203,7 +196,6 @@ func testTheme(t *testing.T) {
style.bold: true
}
`,
themeID: d2themescatalog.FlagshipTerrastruct.ID,
},
}
@ -244,7 +236,7 @@ func run(t *testing.T, tc testCase) {
t.Fatal(err)
}
got, err := d2exporter.Export(ctx, g, tc.themeID, nil)
got, err := d2exporter.Export(ctx, g, nil)
if err != nil {
t.Fatal(err)
}

View file

@ -17,7 +17,7 @@ import (
"oss.terrastruct.com/d2/d2renderers/d2fonts"
"oss.terrastruct.com/d2/d2renderers/d2latex"
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/d2themes"
"oss.terrastruct.com/d2/lib/color"
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/shape"
"oss.terrastruct.com/d2/lib/textmeasure"
@ -336,14 +336,14 @@ func (l ContainerLevel) LabelSize() int {
return d2fonts.FONT_SIZE_M
}
func (obj *Object) GetFill(theme *d2themes.Theme) string {
func (obj *Object) GetFill() string {
level := int(obj.Level())
if obj.IsSequenceDiagramNote() {
return theme.Colors.Neutrals.N7
return color.N7
} else if obj.IsSequenceDiagramGroup() {
return theme.Colors.Neutrals.N5
return color.N5
} else if obj.Parent.IsSequenceDiagram() {
return theme.Colors.B5
return color.B5
}
// fill for spans
@ -351,19 +351,19 @@ func (obj *Object) GetFill(theme *d2themes.Theme) string {
if sd != nil {
level -= int(sd.Level())
if level == 1 {
return theme.Colors.B3
return color.B3
} else if level == 2 {
return theme.Colors.B4
return color.B4
} else if level == 3 {
return theme.Colors.B5
return color.B5
} else if level == 4 {
return theme.Colors.Neutrals.N6
return color.N6
}
return theme.Colors.Neutrals.N7
return color.N7
}
if obj.IsSequenceDiagram() {
return theme.Colors.Neutrals.N7
return color.N7
}
shape := obj.Attributes.Shape.Value
@ -371,65 +371,65 @@ func (obj *Object) GetFill(theme *d2themes.Theme) string {
if shape == "" || strings.EqualFold(shape, d2target.ShapeSquare) || strings.EqualFold(shape, d2target.ShapeCircle) || strings.EqualFold(shape, d2target.ShapeOval) || strings.EqualFold(shape, d2target.ShapeRectangle) {
if level == 1 {
if !obj.IsContainer() {
return theme.Colors.B6
return color.B6
}
return theme.Colors.B4
return color.B4
} else if level == 2 {
return theme.Colors.B5
return color.B5
} else if level == 3 {
return theme.Colors.B6
return color.B6
}
return theme.Colors.Neutrals.N7
return color.N7
}
if strings.EqualFold(shape, d2target.ShapeCylinder) || strings.EqualFold(shape, d2target.ShapeStoredData) || strings.EqualFold(shape, d2target.ShapePackage) {
if level == 1 {
return theme.Colors.AA4
return color.AA4
}
return theme.Colors.AA5
return color.AA5
}
if strings.EqualFold(shape, d2target.ShapeStep) || strings.EqualFold(shape, d2target.ShapePage) || strings.EqualFold(shape, d2target.ShapeDocument) {
if level == 1 {
return theme.Colors.AB4
return color.AB4
}
return theme.Colors.AB5
return color.AB5
}
if strings.EqualFold(shape, d2target.ShapePerson) {
return theme.Colors.B3
return color.B3
}
if strings.EqualFold(shape, d2target.ShapeDiamond) {
return theme.Colors.Neutrals.N4
return color.N4
}
if strings.EqualFold(shape, d2target.ShapeCloud) || strings.EqualFold(shape, d2target.ShapeCallout) {
return theme.Colors.Neutrals.N7
return color.N7
}
if strings.EqualFold(shape, d2target.ShapeQueue) || strings.EqualFold(shape, d2target.ShapeParallelogram) || strings.EqualFold(shape, d2target.ShapeHexagon) {
return theme.Colors.Neutrals.N5
return color.N5
}
if strings.EqualFold(shape, d2target.ShapeSQLTable) || strings.EqualFold(shape, d2target.ShapeClass) {
return theme.Colors.Neutrals.N1
return color.N1
}
return theme.Colors.Neutrals.N7
return color.N7
}
func (obj *Object) GetStroke(theme *d2themes.Theme, dashGapSize interface{}) string {
func (obj *Object) GetStroke(dashGapSize interface{}) string {
shape := obj.Attributes.Shape.Value
if strings.EqualFold(shape, d2target.ShapeCode) ||
strings.EqualFold(shape, d2target.ShapeText) {
return theme.Colors.Neutrals.N1
return color.N1
}
if strings.EqualFold(shape, d2target.ShapeClass) ||
strings.EqualFold(shape, d2target.ShapeSQLTable) {
return theme.Colors.Neutrals.N7
return color.N7
}
if dashGapSize != 0.0 {
return theme.Colors.B2
return color.B2
}
return theme.Colors.B1
return color.B1
}
func (obj *Object) Level() ContainerLevel {
@ -965,11 +965,11 @@ type EdgeReference struct {
ScopeObj *Object `json:"-"`
}
func (e *Edge) GetStroke(theme *d2themes.Theme, dashGapSize interface{}) string {
func (e *Edge) GetStroke(dashGapSize interface{}) string {
if dashGapSize != 0.0 {
return theme.Colors.B2
return color.B2
}
return theme.Colors.B1
return color.B1
}
func (e *Edge) ArrowString() string {

View file

@ -29,7 +29,6 @@ type CompileOptions struct {
// - pre-measured (web setting)
// TODO maybe some will want to configure code font too, but that's much lower priority
FontFamily *d2fonts.FontFamily
ThemeID int64
}
func Compile(ctx context.Context, input string, opts *CompileOptions) (*d2target.Diagram, *d2graph.Graph, error) {
@ -76,7 +75,7 @@ func compile(ctx context.Context, g *d2graph.Graph, opts *CompileOptions) (*d2ta
}
}
d, err := d2exporter.Export(ctx, g, opts.ThemeID, opts.FontFamily)
d, err := d2exporter.Export(ctx, g, opts.FontFamily)
if err != nil {
return nil, err
}

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,7 @@
package d2sketch
import (
"bytes"
"encoding/json"
"fmt"
"regexp"
@ -11,21 +12,23 @@ import (
"github.com/dop251/goja"
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/d2themes"
"oss.terrastruct.com/d2/lib/color"
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/label"
"oss.terrastruct.com/d2/lib/svg"
"oss.terrastruct.com/util-go/go2"
)
//go:embed fillpattern.svg
var fillPattern string
//go:embed rough.js
var roughJS string
//go:embed setup.js
var setupJS string
//go:embed streaks.txt
var streaks string
type Runner goja.Runtime
var baseRoughProps = `fillWeight: 2.0,
@ -36,6 +39,11 @@ seed: 1,`
var floatRE = regexp.MustCompile(`(\d+)\.(\d+)`)
const (
BG_COLOR = color.N7
FG_COLOR = color.N1
)
func (r *Runner) run(js string) (goja.Value, error) {
vm := (*goja.Runtime)(r)
return vm.RunString(js)
@ -53,78 +61,107 @@ func InitSketchVM() (*Runner, error) {
return &r, nil
}
// DefineFillPattern adds a reusable pattern that is overlayed on shapes with
// DefineFillPatterns adds reusable patterns that are overlayed on shapes with
// fill. This gives it a subtle streaky effect that subtly looks hand-drawn but
// not distractingly so.
func DefineFillPattern() string {
return fmt.Sprintf(`<defs>
<pattern id="streaks"
x="0" y="0" width="100" height="100"
patternUnits="userSpaceOnUse" >
%s
</pattern>
</defs>`, fillPattern)
func DefineFillPatterns(buf *bytes.Buffer) {
source := buf.String()
fmt.Fprint(buf, "<defs>")
defineFillPattern(buf, source, "bright", "rgba(0, 0, 0, 0.1)")
defineFillPattern(buf, source, "normal", "rgba(0, 0, 0, 0.16)")
defineFillPattern(buf, source, "dark", "rgba(0, 0, 0, 0.32)")
defineFillPattern(buf, source, "darker", "rgba(255, 255, 255, 0.24)")
fmt.Fprint(buf, "</defs>")
}
func defineFillPattern(buf *bytes.Buffer, source string, luminanceCategory, fill string) {
trigger := fmt.Sprintf(`url(#streaks-%s)`, luminanceCategory)
if strings.Contains(source, trigger) {
fmt.Fprintf(buf, streaks, luminanceCategory, fill)
}
}
func Rect(r *Runner, shape d2target.Shape) (string, error) {
js := fmt.Sprintf(`node = rc.rectangle(0, 0, %d, %d, {
fill: "%s",
stroke: "%s",
fill: "#000",
stroke: "#000",
strokeWidth: %d,
%s
});`, shape.Width, shape.Height, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps)
});`, shape.Width, shape.Height, shape.StrokeWidth, baseRoughProps)
paths, err := computeRoughPathData(r, js)
if err != nil {
return "", err
}
output := ""
pathEl := d2themes.NewThemableElement("path")
pathEl.SetTranslate(float64(shape.Pos.X), float64(shape.Pos.Y))
pathEl.Fill, pathEl.Stroke = d2themes.ShapeTheme(shape)
pathEl.ClassName = "shape"
pathEl.Style = shape.CSSStyle()
for _, p := range paths {
output += fmt.Sprintf(
`<path class="shape" transform="translate(%d %d)" d="%s" style="%s" />`,
shape.Pos.X, shape.Pos.Y, p, shape.CSSStyle(),
)
pathEl.D = p
output += pathEl.Render()
}
output += fmt.Sprintf(
`<rect class="sketch-overlay" transform="translate(%d %d)" width="%d" height="%d" />`,
shape.Pos.X, shape.Pos.Y, shape.Width, shape.Height,
)
sketchOEl := d2themes.NewThemableElement("rect")
sketchOEl.SetTranslate(float64(shape.Pos.X), float64(shape.Pos.Y))
sketchOEl.Width = float64(shape.Width)
sketchOEl.Height = float64(shape.Height)
renderedSO, err := d2themes.NewThemableSketchOverlay(sketchOEl, pathEl.Fill).Render()
if err != nil {
return "", err
}
output += renderedSO
return output, nil
}
func DoubleRect(r *Runner, shape d2target.Shape) (string, error) {
jsBigRect := fmt.Sprintf(`node = rc.rectangle(0, 0, %d, %d, {
fill: "%s",
stroke: "%s",
fill: "#000",
stroke: "#000",
strokeWidth: %d,
%s
});`, shape.Width, shape.Height, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps)
});`, shape.Width, shape.Height, shape.StrokeWidth, baseRoughProps)
pathsBigRect, err := computeRoughPathData(r, jsBigRect)
if err != nil {
return "", err
}
jsSmallRect := fmt.Sprintf(`node = rc.rectangle(0, 0, %d, %d, {
fill: "%s",
stroke: "%s",
fill: "#000",
stroke: "#000",
strokeWidth: %d,
%s
});`, shape.Width-d2target.INNER_BORDER_OFFSET*2, shape.Height-d2target.INNER_BORDER_OFFSET*2, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps)
});`, shape.Width-d2target.INNER_BORDER_OFFSET*2, shape.Height-d2target.INNER_BORDER_OFFSET*2, shape.StrokeWidth, baseRoughProps)
pathsSmallRect, err := computeRoughPathData(r, jsSmallRect)
if err != nil {
return "", err
}
output := ""
pathEl := d2themes.NewThemableElement("path")
pathEl.SetTranslate(float64(shape.Pos.X), float64(shape.Pos.Y))
pathEl.Fill, pathEl.Stroke = d2themes.ShapeTheme(shape)
pathEl.ClassName = "shape"
pathEl.Style = shape.CSSStyle()
for _, p := range pathsBigRect {
output += fmt.Sprintf(
`<path class="shape" transform="translate(%d %d)" d="%s" style="%s" />`,
shape.Pos.X, shape.Pos.Y, p, shape.CSSStyle(),
)
pathEl.D = p
output += pathEl.Render()
}
pathEl = d2themes.NewThemableElement("path")
pathEl.SetTranslate(float64(shape.Pos.X+d2target.INNER_BORDER_OFFSET), float64(shape.Pos.Y+d2target.INNER_BORDER_OFFSET))
pathEl.Fill, pathEl.Stroke = d2themes.ShapeTheme(shape)
pathEl.ClassName = "shape"
pathEl.Style = shape.CSSStyle()
for _, p := range pathsSmallRect {
output += fmt.Sprintf(
`<path class="shape" transform="translate(%d %d)" d="%s" style="%s" />`,
shape.Pos.X+d2target.INNER_BORDER_OFFSET, shape.Pos.Y+d2target.INNER_BORDER_OFFSET, p, shape.CSSStyle(),
)
pathEl.D = p
output += pathEl.Render()
}
output += fmt.Sprintf(
`<rect class="sketch-overlay" transform="translate(%d %d)" width="%d" height="%d" />`,
shape.Pos.X, shape.Pos.Y, shape.Width, shape.Height,
@ -134,42 +171,55 @@ func DoubleRect(r *Runner, shape d2target.Shape) (string, error) {
func Oval(r *Runner, shape d2target.Shape) (string, error) {
js := fmt.Sprintf(`node = rc.ellipse(%d, %d, %d, %d, {
fill: "%s",
stroke: "%s",
fill: "#000",
stroke: "#000",
strokeWidth: %d,
%s
});`, shape.Width/2, shape.Height/2, shape.Width, shape.Height, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps)
});`, shape.Width/2, shape.Height/2, shape.Width, shape.Height, shape.StrokeWidth, baseRoughProps)
paths, err := computeRoughPathData(r, js)
if err != nil {
return "", err
}
output := ""
pathEl := d2themes.NewThemableElement("path")
pathEl.SetTranslate(float64(shape.Pos.X), float64(shape.Pos.Y))
pathEl.Fill, pathEl.Stroke = d2themes.ShapeTheme(shape)
pathEl.ClassName = "shape"
pathEl.Style = shape.CSSStyle()
for _, p := range paths {
output += fmt.Sprintf(
`<path class="shape" transform="translate(%d %d)" d="%s" style="%s" />`,
shape.Pos.X, shape.Pos.Y, p, shape.CSSStyle(),
)
pathEl.D = p
output += pathEl.Render()
}
output += fmt.Sprintf(
`<ellipse class="sketch-overlay" transform="translate(%d %d)" rx="%d" ry="%d" />`,
shape.Pos.X+shape.Width/2, shape.Pos.Y+shape.Height/2, shape.Width/2, shape.Height/2,
)
soElement := d2themes.NewThemableElement("ellipse")
soElement.SetTranslate(float64(shape.Pos.X+shape.Width/2), float64(shape.Pos.Y+shape.Height/2))
soElement.Rx = float64(shape.Width / 2)
soElement.Ry = float64(shape.Height / 2)
renderedSO, err := d2themes.NewThemableSketchOverlay(
soElement,
pathEl.Fill,
).Render()
if err != nil {
return "", err
}
output += renderedSO
return output, nil
}
func DoubleOval(r *Runner, shape d2target.Shape) (string, error) {
jsBigCircle := fmt.Sprintf(`node = rc.ellipse(%d, %d, %d, %d, {
fill: "%s",
stroke: "%s",
fill: "#000",
stroke: "#000",
strokeWidth: %d,
%s
});`, shape.Width/2, shape.Height/2, shape.Width, shape.Height, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps)
});`, shape.Width/2, shape.Height/2, shape.Width, shape.Height, shape.StrokeWidth, baseRoughProps)
jsSmallCircle := fmt.Sprintf(`node = rc.ellipse(%d, %d, %d, %d, {
fill: "%s",
stroke: "%s",
fill: "#000",
stroke: "#000",
strokeWidth: %d,
%s
});`, shape.Width/2, shape.Height/2, shape.Width-d2target.INNER_BORDER_OFFSET*2, shape.Height-d2target.INNER_BORDER_OFFSET*2, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps)
});`, shape.Width/2, shape.Height/2, shape.Width-d2target.INNER_BORDER_OFFSET*2, shape.Height-d2target.INNER_BORDER_OFFSET*2, shape.StrokeWidth, baseRoughProps)
pathsBigCircle, err := computeRoughPathData(r, jsBigCircle)
if err != nil {
return "", err
@ -178,19 +228,29 @@ func DoubleOval(r *Runner, shape d2target.Shape) (string, error) {
if err != nil {
return "", err
}
output := ""
pathEl := d2themes.NewThemableElement("path")
pathEl.SetTranslate(float64(shape.Pos.X), float64(shape.Pos.Y))
pathEl.Fill, pathEl.Stroke = d2themes.ShapeTheme(shape)
pathEl.ClassName = "shape"
pathEl.Style = shape.CSSStyle()
for _, p := range pathsBigCircle {
output += fmt.Sprintf(
`<path class="shape" transform="translate(%d %d)" d="%s" style="%s" />`,
shape.Pos.X, shape.Pos.Y, p, shape.CSSStyle(),
)
pathEl.D = p
output += pathEl.Render()
}
pathEl = d2themes.NewThemableElement("path")
pathEl.SetTranslate(float64(shape.Pos.X), float64(shape.Pos.Y))
pathEl.Fill, pathEl.Stroke = d2themes.ShapeTheme(shape)
pathEl.ClassName = "shape"
pathEl.Style = shape.CSSStyle()
for _, p := range pathsSmallCircle {
output += fmt.Sprintf(
`<path class="shape" transform="translate(%d %d)" d="%s" style="%s" />`,
shape.Pos.X, shape.Pos.Y, p, shape.CSSStyle(),
)
pathEl.D = p
output += pathEl.Render()
}
output += fmt.Sprintf(
`<ellipse class="sketch-overlay" transform="translate(%d %d)" rx="%d" ry="%d" />`,
shape.Pos.X+shape.Width/2, shape.Pos.Y+shape.Height/2, shape.Width/2, shape.Height/2,
@ -203,26 +263,35 @@ func Paths(r *Runner, shape d2target.Shape, paths []string) (string, error) {
output := ""
for _, path := range paths {
js := fmt.Sprintf(`node = rc.path("%s", {
fill: "%s",
stroke: "%s",
fill: "#000",
stroke: "#000",
strokeWidth: %d,
%s
});`, path, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps)
});`, path, shape.StrokeWidth, baseRoughProps)
sketchPaths, err := computeRoughPathData(r, js)
if err != nil {
return "", err
}
pathEl := d2themes.NewThemableElement("path")
pathEl.Fill, pathEl.Stroke = d2themes.ShapeTheme(shape)
pathEl.ClassName = "shape"
pathEl.Style = shape.CSSStyle()
for _, p := range sketchPaths {
output += fmt.Sprintf(
`<path class="shape" d="%s" style="%s" />`,
p, shape.CSSStyle(),
)
pathEl.D = p
output += pathEl.Render()
}
soElement := d2themes.NewThemableElement("path")
for _, p := range sketchPaths {
output += fmt.Sprintf(
`<path class="sketch-overlay" d="%s" />`,
p,
)
soElement.D = p
renderedSO, err := d2themes.NewThemableSketchOverlay(
soElement,
pathEl.Fill,
).Render()
if err != nil {
return "", err
}
output += renderedSO
}
}
return output, nil
@ -240,11 +309,16 @@ func Connection(r *Runner, connection d2target.Connection, path, attrs string) (
if connection.Animated {
animatedClass = " animated-connection"
}
pathEl := d2themes.NewThemableElement("path")
pathEl.Fill = color.None
pathEl.Stroke = connection.Stroke
pathEl.ClassName = fmt.Sprintf("connection%s", animatedClass)
pathEl.Style = connection.CSSStyle()
pathEl.Attributes = attrs
for _, p := range paths {
output += fmt.Sprintf(
`<path class="connection%s" fill="none" d="%s" style="%s" %s/>`,
animatedClass, p, connection.CSSStyle(), attrs,
)
pathEl.D = p
output += pathEl.Render()
}
return output, nil
}
@ -253,20 +327,23 @@ func Connection(r *Runner, connection d2target.Connection, path, attrs string) (
func Table(r *Runner, shape d2target.Shape) (string, error) {
output := ""
js := fmt.Sprintf(`node = rc.rectangle(0, 0, %d, %d, {
fill: "%s",
stroke: "%s",
fill: "#000",
stroke: "#000",
strokeWidth: %d,
%s
});`, shape.Width, shape.Height, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps)
});`, shape.Width, shape.Height, shape.StrokeWidth, baseRoughProps)
paths, err := computeRoughPathData(r, js)
if err != nil {
return "", err
}
pathEl := d2themes.NewThemableElement("path")
pathEl.SetTranslate(float64(shape.Pos.X), float64(shape.Pos.Y))
pathEl.Fill, pathEl.Stroke = d2themes.ShapeTheme(shape)
pathEl.ClassName = "shape"
pathEl.Style = shape.CSSStyle()
for _, p := range paths {
output += fmt.Sprintf(
`<path class="shape" transform="translate(%d %d)" d="%s" style="%s" />`,
shape.Pos.X, shape.Pos.Y, p, shape.CSSStyle(),
)
pathEl.D = p
output += pathEl.Render()
}
box := geo.NewBox(
@ -278,18 +355,20 @@ func Table(r *Runner, shape d2target.Shape) (string, error) {
headerBox := geo.NewBox(box.TopLeft, box.Width, rowHeight)
js = fmt.Sprintf(`node = rc.rectangle(0, 0, %d, %f, {
fill: "%s",
fill: "#000",
%s
});`, shape.Width, rowHeight, shape.Fill, baseRoughProps)
});`, shape.Width, rowHeight, baseRoughProps)
paths, err = computeRoughPathData(r, js)
if err != nil {
return "", err
}
pathEl = d2themes.NewThemableElement("path")
pathEl.SetTranslate(float64(shape.Pos.X), float64(shape.Pos.Y))
pathEl.Fill = shape.Fill
pathEl.ClassName = "class_header"
for _, p := range paths {
output += fmt.Sprintf(
`<path class="class_header" transform="translate(%d %d)" d="%s" style="fill:%s" />`,
shape.Pos.X, shape.Pos.Y, p, shape.Fill,
)
pathEl.D = p
output += pathEl.Render()
}
if shape.Label != "" {
@ -300,17 +379,16 @@ func Table(r *Runner, shape d2target.Shape) (string, error) {
float64(shape.LabelHeight),
)
output += fmt.Sprintf(`<text class="%s" x="%f" y="%f" style="%s">%s</text>`,
"text",
tl.X,
tl.Y+float64(shape.LabelHeight)*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s",
"start",
4+shape.FontSize,
shape.Stroke,
),
svg.EscapeText(shape.Label),
textEl := d2themes.NewThemableElement("text")
textEl.X = tl.X
textEl.Y = tl.Y + float64(shape.LabelHeight)*3/4
textEl.Fill = shape.Stroke
textEl.ClassName = "text"
textEl.Style = fmt.Sprintf("text-anchor:%s;font-size:%vpx",
"start", 4+shape.FontSize,
)
textEl.Content = svg.EscapeText(shape.Label)
output += textEl.Render()
}
var longestNameWidth int
@ -334,26 +412,26 @@ func Table(r *Runner, shape d2target.Shape) (string, error) {
float64(shape.FontSize),
)
output += strings.Join([]string{
fmt.Sprintf(`<text class="text" x="%f" y="%f" style="%s">%s</text>`,
nameTL.X,
nameTL.Y+float64(shape.FontSize)*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s", "start", float64(shape.FontSize), shape.PrimaryAccentColor),
svg.EscapeText(f.Name.Label),
),
fmt.Sprintf(`<text class="text" x="%f" y="%f" style="%s">%s</text>`,
nameTL.X+float64(longestNameWidth)+2*d2target.NamePadding,
nameTL.Y+float64(shape.FontSize)*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s", "start", float64(shape.FontSize), shape.NeutralAccentColor),
svg.EscapeText(f.Type.Label),
),
fmt.Sprintf(`<text class="text" x="%f" y="%f" style="%s">%s</text>`,
constraintTR.X,
constraintTR.Y+float64(shape.FontSize)*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s;letter-spacing:2px;", "end", float64(shape.FontSize), shape.SecondaryAccentColor),
f.ConstraintAbbr(),
),
}, "\n")
textEl := d2themes.NewThemableElement("text")
textEl.X = nameTL.X
textEl.Y = nameTL.Y + float64(shape.FontSize)*3/4
textEl.Fill = shape.PrimaryAccentColor
textEl.ClassName = "text"
textEl.Style = fmt.Sprintf("text-anchor:%s;font-size:%vpx", "start", float64(shape.FontSize))
textEl.Content = svg.EscapeText(f.Name.Label)
output += textEl.Render()
textEl.X = nameTL.X + float64(longestNameWidth) + 2*d2target.NamePadding
textEl.Fill = shape.NeutralAccentColor
textEl.Content = svg.EscapeText(f.Type.Label)
output += textEl.Render()
textEl.X = constraintTR.X
textEl.Y = constraintTR.Y + float64(shape.FontSize)*3/4
textEl.Fill = shape.SecondaryAccentColor
textEl.Style = fmt.Sprintf("text-anchor:%s;font-size:%vpx;letter-spacing:2px", "end", float64(shape.FontSize))
textEl.Content = f.ConstraintAbbr()
output += textEl.Render()
rowBox.TopLeft.Y += rowHeight
@ -364,37 +442,47 @@ func Table(r *Runner, shape d2target.Shape) (string, error) {
if err != nil {
return "", err
}
pathEl := d2themes.NewThemableElement("path")
pathEl.Fill = shape.Fill
for _, p := range paths {
output += fmt.Sprintf(
`<path d="%s" style="fill:%s" />`,
p, shape.Fill,
)
pathEl.D = p
output += pathEl.Render()
}
}
output += fmt.Sprintf(
`<rect class="sketch-overlay" transform="translate(%d %d)" width="%d" height="%d" />`,
shape.Pos.X, shape.Pos.Y, shape.Width, shape.Height,
)
sketchOEl := d2themes.NewThemableElement("rect")
sketchOEl.SetTranslate(float64(shape.Pos.X), float64(shape.Pos.Y))
sketchOEl.Width = float64(shape.Width)
sketchOEl.Height = float64(shape.Height)
renderedSO, err := d2themes.NewThemableSketchOverlay(sketchOEl, pathEl.Fill).Render()
if err != nil {
return "", err
}
output += renderedSO
return output, nil
}
func Class(r *Runner, shape d2target.Shape) (string, error) {
output := ""
js := fmt.Sprintf(`node = rc.rectangle(0, 0, %d, %d, {
fill: "%s",
stroke: "%s",
fill: "#000",
stroke: "#000",
strokeWidth: %d,
%s
});`, shape.Width, shape.Height, shape.Fill, shape.Stroke, shape.StrokeWidth, baseRoughProps)
});`, shape.Width, shape.Height, shape.StrokeWidth, baseRoughProps)
paths, err := computeRoughPathData(r, js)
if err != nil {
return "", err
}
pathEl := d2themes.NewThemableElement("path")
pathEl.SetTranslate(float64(shape.Pos.X), float64(shape.Pos.Y))
pathEl.Fill, pathEl.Stroke = d2themes.ShapeTheme(shape)
pathEl.ClassName = "shape"
pathEl.Style = shape.CSSStyle()
for _, p := range paths {
output += fmt.Sprintf(
`<path class="shape" transform="translate(%d %d)" d="%s" style="%s" />`,
shape.Pos.X, shape.Pos.Y, p, shape.CSSStyle(),
)
pathEl.D = p
output += pathEl.Render()
}
box := geo.NewBox(
@ -407,24 +495,31 @@ func Class(r *Runner, shape d2target.Shape) (string, error) {
headerBox := geo.NewBox(box.TopLeft, box.Width, 2*rowHeight)
js = fmt.Sprintf(`node = rc.rectangle(0, 0, %d, %f, {
fill: "%s",
fill: "#000",
%s
});`, shape.Width, headerBox.Height, shape.Fill, baseRoughProps)
});`, shape.Width, headerBox.Height, baseRoughProps)
paths, err = computeRoughPathData(r, js)
if err != nil {
return "", err
}
pathEl = d2themes.NewThemableElement("path")
pathEl.SetTranslate(float64(shape.Pos.X), float64(shape.Pos.Y))
pathEl.Fill = shape.Fill
pathEl.ClassName = "class_header"
for _, p := range paths {
output += fmt.Sprintf(
`<path class="class_header" transform="translate(%d %d)" d="%s" style="fill:%s" />`,
shape.Pos.X, shape.Pos.Y, p, shape.Fill,
)
pathEl.D = p
output += pathEl.Render()
}
output += fmt.Sprintf(
`<rect class="sketch-overlay" transform="translate(%d %d)" width="%d" height="%f" />`,
shape.Pos.X, shape.Pos.Y, shape.Width, headerBox.Height,
)
sketchOEl := d2themes.NewThemableElement("rect")
sketchOEl.SetTranslate(float64(shape.Pos.X), float64(shape.Pos.Y))
sketchOEl.Width = float64(shape.Width)
sketchOEl.Height = headerBox.Height
renderedSO, err := d2themes.NewThemableSketchOverlay(sketchOEl, pathEl.Fill).Render()
if err != nil {
return "", err
}
output += renderedSO
if shape.Label != "" {
tl := label.InsideMiddleCenter.GetPointOnBox(
@ -434,17 +529,17 @@ func Class(r *Runner, shape d2target.Shape) (string, error) {
float64(shape.LabelHeight),
)
output += fmt.Sprintf(`<text class="%s" x="%f" y="%f" style="%s">%s</text>`,
"text-mono",
tl.X+float64(shape.LabelWidth)/2,
tl.Y+float64(shape.LabelHeight)*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s",
"middle",
4+shape.FontSize,
shape.Stroke,
),
svg.EscapeText(shape.Label),
textEl := d2themes.NewThemableElement("text")
textEl.X = tl.X + float64(shape.LabelWidth)/2
textEl.Y = tl.Y + float64(shape.LabelHeight)*3/4
textEl.Fill = shape.Stroke
textEl.ClassName = "text-mono"
textEl.Style = fmt.Sprintf("text-anchor:%s;font-size:%vpx",
"middle",
4+shape.FontSize,
)
textEl.Content = svg.EscapeText(shape.Label)
output += textEl.Render()
}
rowBox := geo.NewBox(box.TopLeft.Copy(), box.Width, rowHeight)
@ -461,11 +556,12 @@ func Class(r *Runner, shape d2target.Shape) (string, error) {
if err != nil {
return "", err
}
pathEl = d2themes.NewThemableElement("path")
pathEl.Fill = shape.Fill
pathEl.ClassName = "class_header"
for _, p := range paths {
output += fmt.Sprintf(
`<path class="class_header" d="%s" style="fill:%s" />`,
p, shape.Fill,
)
pathEl.D = p
output += pathEl.Render()
}
for _, m := range shape.Methods {
@ -491,28 +587,27 @@ func classRow(shape d2target.Shape, box *geo.Box, prefix, nameText, typeText str
fontSize,
)
output += strings.Join([]string{
fmt.Sprintf(`<text class="text-mono" x="%f" y="%f" style="%s">%s</text>`,
prefixTL.X,
prefixTL.Y+fontSize*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s", "start", fontSize, shape.PrimaryAccentColor),
prefix,
),
textEl := d2themes.NewThemableElement("text")
textEl.X = prefixTL.X
textEl.Y = prefixTL.Y + fontSize*3/4
textEl.Fill = shape.PrimaryAccentColor
textEl.ClassName = "text-mono"
textEl.Style = fmt.Sprintf("text-anchor:%s;font-size:%vpx", "start", fontSize)
textEl.Content = prefix
output += textEl.Render()
fmt.Sprintf(`<text class="text-mono" x="%f" y="%f" style="%s">%s</text>`,
prefixTL.X+d2target.PrefixWidth,
prefixTL.Y+fontSize*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s", "start", fontSize, shape.Fill),
svg.EscapeText(nameText),
),
textEl.X = prefixTL.X + d2target.PrefixWidth
textEl.Fill = shape.Fill
textEl.Content = svg.EscapeText(nameText)
output += textEl.Render()
textEl.X = typeTR.X
textEl.Y = typeTR.Y + fontSize*3/4
textEl.Fill = shape.SecondaryAccentColor
textEl.Style = fmt.Sprintf("text-anchor:%s;font-size:%vpx", "end", fontSize)
textEl.Content = svg.EscapeText(typeText)
output += textEl.Render()
fmt.Sprintf(`<text class="text-mono" x="%f" y="%f" style="%s">%s</text>`,
typeTR.X,
typeTR.Y+fontSize*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s;", "end", fontSize, shape.SecondaryAccentColor),
svg.EscapeText(typeText),
),
}, "\n")
return output
}
@ -551,12 +646,6 @@ type roughPath struct {
func (rp roughPath) StyleCSS() string {
style := ""
if rp.Style.Fill != "" {
style += fmt.Sprintf("fill:%s;", rp.Style.Fill)
}
if rp.Style.Stroke != "" {
style += fmt.Sprintf("stroke:%s;", rp.Style.Stroke)
}
if rp.Style.StrokeWidth != "" {
style += fmt.Sprintf("stroke-width:%s;", rp.Style.StrokeWidth)
}
@ -617,10 +706,11 @@ func ArrowheadJS(r *Runner, arrowhead d2target.Arrowhead, stroke string, strokeW
)
case d2target.DiamondArrowhead:
arrowJS = fmt.Sprintf(
`node = rc.polygon(%s, { strokeWidth: %d, stroke: "%s", fill: "white", fillStyle: "solid", seed: 1 })`,
`node = rc.polygon(%s, { strokeWidth: %d, stroke: "%s", fill: "%s", fillStyle: "solid", seed: 1 })`,
`[[-20, 0], [-10, 5], [0, 0], [-10, -5], [-20, 0]]`,
strokeWidth,
stroke,
BG_COLOR,
)
case d2target.FilledDiamondArrowhead:
arrowJS = fmt.Sprintf(
@ -648,9 +738,10 @@ func ArrowheadJS(r *Runner, arrowhead d2target.Arrowhead, stroke string, strokeW
stroke,
)
extraJS = fmt.Sprintf(
`node = rc.circle(-20, 0, 8, { strokeWidth: %d, stroke: "%s", fill: "white", fillStyle: "solid", fillWeight: 1, seed: 4 })`,
`node = rc.circle(-20, 0, 8, { strokeWidth: %d, stroke: "%s", fill: "%s", fillStyle: "solid", fillWeight: 1, seed: 4 })`,
strokeWidth,
stroke,
BG_COLOR,
)
case d2target.CfOneRequired:
arrowJS = fmt.Sprintf(
@ -669,9 +760,10 @@ func ArrowheadJS(r *Runner, arrowhead d2target.Arrowhead, stroke string, strokeW
stroke,
)
extraJS = fmt.Sprintf(
`node = rc.circle(-20, 0, 8, { strokeWidth: %d, stroke: "%s", fill: "white", fillStyle: "solid", fillWeight: 1, seed: 5 })`,
`node = rc.circle(-20, 0, 8, { strokeWidth: %d, stroke: "%s", fill: "%s", fillStyle: "solid", fillWeight: 1, seed: 5 })`,
strokeWidth,
stroke,
BG_COLOR,
)
}
return
@ -706,13 +798,15 @@ func Arrowheads(r *Runner, connection d2target.Connection, srcAdj, dstAdj *geo.P
roughPaths = append(roughPaths, extraPaths...)
}
pathEl := d2themes.NewThemableElement("path")
pathEl.ClassName = "connection"
pathEl.Attributes = transform
for _, rp := range roughPaths {
pathStr := fmt.Sprintf(`<path class="connection" d="%s" style="%s" %s/>`,
rp.Attrs.D,
rp.StyleCSS(),
transform,
)
arrowPaths = append(arrowPaths, pathStr)
pathEl.D = rp.Attrs.D
pathEl.Fill = rp.Style.Fill
pathEl.Stroke = rp.Style.Stroke
pathEl.Style = rp.StyleCSS()
arrowPaths = append(arrowPaths, pathEl.Render())
}
}
@ -743,13 +837,15 @@ func Arrowheads(r *Runner, connection d2target.Connection, srcAdj, dstAdj *geo.P
roughPaths = append(roughPaths, extraPaths...)
}
pathEl := d2themes.NewThemableElement("path")
pathEl.ClassName = "connection"
pathEl.Attributes = transform
for _, rp := range roughPaths {
pathStr := fmt.Sprintf(`<path class="connection" d="%s" style="%s" %s/>`,
rp.Attrs.D,
rp.StyleCSS(),
transform,
)
arrowPaths = append(arrowPaths, pathStr)
pathEl.D = rp.Attrs.D
pathEl.Fill = rp.Style.Fill
pathEl.Stroke = rp.Style.Stroke
pathEl.Style = rp.StyleCSS()
arrowPaths = append(arrowPaths, pathEl.Render())
}
}

View file

@ -14,6 +14,7 @@ import (
tassert "github.com/stretchr/testify/assert"
"oss.terrastruct.com/util-go/assert"
"oss.terrastruct.com/util-go/diff"
"oss.terrastruct.com/util-go/go2"
"oss.terrastruct.com/d2/d2layouts/d2dagrelayout"
@ -470,6 +471,485 @@ users: {
last_login: datetime
style.opacity: 0.4
}
`,
},
{
name: "overlay",
script: `bright: {
style.stroke: "#000"
style.font-color: "#000"
style.fill: "#fff"
}
normal: {
style.stroke: "#000"
style.font-color: "#000"
style.fill: "#ccc"
}
dark: {
style.stroke: "#000"
style.font-color: "#fff"
style.fill: "#555"
}
darker: {
style.stroke: "#000"
style.font-color: "#fff"
style.fill: "#000"
}
`,
},
{
name: "basic dark",
themeID: 200,
script: `a -> b
`,
},
{
name: "child to child dark",
themeID: 200,
script: `winter.snow -> summer.sun
`,
},
{
name: "animated dark",
themeID: 200,
script: `winter.snow -> summer.sun -> trees -> winter.snow: { style.animated: true }
`,
},
{
name: "connection label dark",
themeID: 200,
script: `a -> b: hello
`,
},
{
name: "crows feet dark",
themeID: 200,
script: `a1 <-> b1: {
style.stroke-width: 1
source-arrowhead: {
shape: cf-many
}
target-arrowhead: {
shape: cf-many
}
}
a2 <-> b2: {
style.stroke-width: 3
source-arrowhead: {
shape: cf-many
}
target-arrowhead: {
shape: cf-many
}
}
a3 <-> b3: {
style.stroke-width: 6
source-arrowhead: {
shape: cf-many
}
target-arrowhead: {
shape: cf-many
}
}
c1 <-> d1: {
style.stroke-width: 1
source-arrowhead: {
shape: cf-many-required
}
target-arrowhead: {
shape: cf-many-required
}
}
c2 <-> d2: {
style.stroke-width: 3
source-arrowhead: {
shape: cf-many-required
}
target-arrowhead: {
shape: cf-many-required
}
}
c3 <-> d3: {
style.stroke-width: 6
source-arrowhead: {
shape: cf-many-required
}
target-arrowhead: {
shape: cf-many-required
}
}
e1 <-> f1: {
style.stroke-width: 1
source-arrowhead: {
shape: cf-one
}
target-arrowhead: {
shape: cf-one
}
}
e2 <-> f2: {
style.stroke-width: 3
source-arrowhead: {
shape: cf-one
}
target-arrowhead: {
shape: cf-one
}
}
e3 <-> f3: {
style.stroke-width: 6
source-arrowhead: {
shape: cf-one
}
target-arrowhead: {
shape: cf-one
}
}
g1 <-> h1: {
style.stroke-width: 1
source-arrowhead: {
shape: cf-one-required
}
target-arrowhead: {
shape: cf-one-required
}
}
g2 <-> h2: {
style.stroke-width: 3
source-arrowhead: {
shape: cf-one-required
}
target-arrowhead: {
shape: cf-one-required
}
}
g3 <-> h3: {
style.stroke-width: 6
source-arrowhead: {
shape: cf-one-required
}
target-arrowhead: {
shape: cf-one-required
}
}
c <-> d <-> f: {
style.stroke-width: 1
style.stroke: "orange"
source-arrowhead: {
shape: cf-many-required
}
target-arrowhead: {
shape: cf-one
}
}
`,
},
{
name: "twitter dark",
themeID: 200,
script: `timeline mixer: "" {
explanation: |md
## **Timeline mixer**
- Inject ads, who-to-follow, onboarding
- Conversation module
- Cursoring,pagination
- Tweat deduplication
- Served data logging
|
}
People discovery: "People discovery \nservice"
admixer: Ad mixer {
style.fill: "#c1a2f3"
}
onboarding service: "Onboarding \nservice"
timeline mixer -> People discovery
timeline mixer -> onboarding service
timeline mixer -> admixer
container0: "" {
graphql
comment
tlsapi
}
container0.graphql: GraphQL\nFederated Strato Column {
shape: image
icon: https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/GraphQL_Logo.svg/1200px-GraphQL_Logo.svg.png
}
container0.comment: |md
## Tweet/user content hydration, visibility filtering
|
container0.tlsapi: TLS-API (being deprecated)
container0.graphql -> timeline mixer
timeline mixer <- container0.tlsapi
twitter fe: "Twitter Frontend " {
icon: https://icons.terrastruct.com/social/013-twitter-1.svg
shape: image
}
twitter fe -> container0.graphql: iPhone web
twitter fe -> container0.tlsapi: HTTP Android
web: Web {
icon: https://icons.terrastruct.com/azure/Web%20Service%20Color/App%20Service%20Domains.svg
shape: image
}
Iphone: {
icon: 'https://ss7.vzw.com/is/image/VerizonWireless/apple-iphone-12-64gb-purple-53017-mjn13ll-a?$device-lg$'
shape: image
}
Android: {
icon: https://cdn4.iconfinder.com/data/icons/smart-phones-technologies/512/android-phone.png
shape: image
}
web -> twitter fe
timeline scorer: "Timeline\nScorer" {
style.fill "#ffdef1"
}
home ranker: Home Ranker
timeline service: Timeline Service
timeline mixer -> timeline scorer: Thrift RPC
timeline mixer -> home ranker: {
style.stroke-dash: 4
style.stroke: "#000E3D"
}
timeline mixer -> timeline service
home mixer: Home mixer {
# style.fill "#c1a2f3"
}
container0.graphql -> home mixer: {
style.stroke-dash: 4
style.stroke: "#000E3D"
}
home mixer -> timeline scorer
home mixer -> home ranker: {
style.stroke-dash: 4
style.stroke: "#000E3D"
}
home mixer -> timeline service
manhattan 2: Manhattan
gizmoduck: Gizmoduck
socialgraph: Social graph
tweetypie: Tweety Pie
home mixer -> manhattan 2
home mixer -> gizmoduck
home mixer -> socialgraph
home mixer -> tweetypie
Iphone -> twitter fe
Android -> twitter fe
prediction service2: Prediction Service {
shape: image
icon: https://cdn-icons-png.flaticon.com/512/6461/6461819.png
}
home scorer: Home Scorer {
style.fill "#ffdef1"
}
manhattan: Manhattan
memcache: Memcache {
icon: https://d1q6f0aelx0por.cloudfront.net/product-logos/de041504-0ddb-43f6-b89e-fe04403cca8d-memcached.png
}
fetch: Fetch {
style.multiple: true
shape: step
}
feature: Feature {
style.multiple: true
shape: step
}
scoring: Scoring {
style.multiple: true
shape: step
}
fetch -> feature
feature -> scoring
prediction service: Prediction Service {
shape: image
icon: https://cdn-icons-png.flaticon.com/512/6461/6461819.png
}
scoring -> prediction service
fetch -> container2.crmixer
home scorer -> manhattan: ""
home scorer -> memcache: ""
home scorer -> prediction service2
home ranker -> home scorer
home ranker -> container2.crmixer: Candidate Fetch
container2: "" {
style.stroke: "#000E3D"
style.fill: "#ffffff"
crmixer: CrMixer {
style.fill: "#F7F8FE"
}
earlybird: EarlyBird
utag: Utag
space: Space
communities: Communities
}
etc: ...etc
home scorer -> etc: Feature Hydration
feature -> manhattan
feature -> memcache
feature -> etc: Candidate sources
`,
},
{
name: "all_shapes dark",
themeID: 200,
script: `
rectangle: {shape: "rectangle"}
square: {shape: "square"}
page: {shape: "page"}
parallelogram: {shape: "parallelogram"}
document: {shape: "document"}
cylinder: {shape: "cylinder"}
queue: {shape: "queue"}
package: {shape: "package"}
step: {shape: "step"}
callout: {shape: "callout"}
stored_data: {shape: "stored_data"}
person: {shape: "person"}
diamond: {shape: "diamond"}
oval: {shape: "oval"}
circle: {shape: "circle"}
hexagon: {shape: "hexagon"}
cloud: {shape: "cloud"}
rectangle -> square -> page
parallelogram -> document -> cylinder
queue -> package -> step
callout -> stored_data -> person
diamond -> oval -> circle
hexagon -> cloud
`,
},
{
name: "sql_tables dark",
themeID: 200,
script: `users: {
shape: sql_table
id: int
name: string
email: string
password: string
last_login: datetime
}
products: {
shape: sql_table
id: int
price: decimal
sku: string
name: string
}
orders: {
shape: sql_table
id: int
user_id: int
product_id: int
}
shipments: {
shape: sql_table
id: int
order_id: int
tracking_number: string {constraint: primary_key}
status: string
}
users.id <-> orders.user_id
products.id <-> orders.product_id
shipments.order_id <-> orders.id`,
},
{
name: "class dark",
themeID: 200,
script: `manager: BatchManager {
shape: class
-num: int
-timeout: int
-pid
+getStatus(): Enum
+getJobs(): "Job[]"
+setTimeout(seconds int)
}
`,
},
{
name: "arrowheads dark",
themeID: 200,
script: `
a: ""
b: ""
a.1 -- b.1: none
a.2 <-> b.2: arrow {
source-arrowhead.shape: arrow
target-arrowhead.shape: arrow
}
a.3 <-> b.3: triangle {
source-arrowhead.shape: triangle
target-arrowhead.shape: triangle
}
a.4 <-> b.4: diamond {
source-arrowhead.shape: diamond
target-arrowhead.shape: diamond
}
a.5 <-> b.5: diamond filled {
source-arrowhead: {
shape: diamond
style.filled: true
}
target-arrowhead: {
shape: diamond
style.filled: true
}
}
a.6 <-> b.6: cf-many {
source-arrowhead.shape: cf-many
target-arrowhead.shape: cf-many
}
a.7 <-> b.7: cf-many-required {
source-arrowhead.shape: cf-many-required
target-arrowhead.shape: cf-many-required
}
a.8 <-> b.8: cf-one {
source-arrowhead.shape: cf-one
target-arrowhead.shape: cf-one
}
a.9 <-> b.9: cf-one-required {
source-arrowhead.shape: cf-one-required
target-arrowhead.shape: cf-one-required
}
`,
},
{
name: "opacity dark",
themeID: 200,
script: `x.style.opacity: 0.4
y: |md
linux: because a PC is a terrible thing to waste
| {
style.opacity: 0.4
}
x -> a: {
label: You don't have to know how the computer works,\njust how to work the computer.
style.opacity: 0.4
}
users: {
shape: sql_table
last_login: datetime
style.opacity: 0.4
}
`,
},
}
@ -477,9 +957,10 @@ users: {
}
type testCase struct {
name string
script string
skip bool
name string
themeID int64
script string
skip bool
}
func runa(t *testing.T, tcs []testCase) {
@ -508,7 +989,6 @@ func run(t *testing.T, tc testCase) {
diagram, _, err := d2lib.Compile(ctx, tc.script, &d2lib.CompileOptions{
Ruler: ruler,
ThemeID: 0,
Layout: d2dagrelayout.DefaultLayout,
FontFamily: go2.Pointer(d2fonts.HandDrawn),
})
@ -520,8 +1000,9 @@ func run(t *testing.T, tc testCase) {
pathGotSVG := filepath.Join(dataPath, "sketch.got.svg")
svgBytes, err := d2svg.Render(diagram, &d2svg.RenderOpts{
Pad: d2svg.DEFAULT_PADDING,
Sketch: true,
Pad: d2svg.DEFAULT_PADDING,
Sketch: true,
ThemeID: tc.themeID,
})
assert.Success(t, err)
err = os.MkdirAll(dataPath, 0755)
@ -533,4 +1014,7 @@ func run(t *testing.T, tc testCase) {
var xmlParsed interface{}
err = xml.Unmarshal(svgBytes, &xmlParsed)
assert.Success(t, err)
err = diff.Testdata(filepath.Join(dataPath, "sketch"), ".svg", svgBytes)
assert.Success(t, err)
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 267 KiB

After

Width:  |  Height:  |  Size: 298 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 289 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 253 KiB

After

Width:  |  Height:  |  Size: 284 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 275 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 303 KiB

After

Width:  |  Height:  |  Size: 334 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 325 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 196 KiB

After

Width:  |  Height:  |  Size: 228 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 218 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 280 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 270 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 196 KiB

After

Width:  |  Height:  |  Size: 227 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 218 KiB

View file

@ -1,136 +0,0 @@
{
"name": "",
"fontFamily": "HandDrawn",
"shapes": [
{
"id": "a",
"type": "",
"pos": {
"x": 1,
"y": 0
},
"width": 114,
"height": 126,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"shadow": false,
"3d": false,
"multiple": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "a",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 14,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 1
},
{
"id": "b",
"type": "",
"pos": {
"x": 0,
"y": 226
},
"width": 115,
"height": 126,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"shadow": false,
"3d": false,
"multiple": false,
"tooltip": "",
"link": "",
"icon": null,
"iconPosition": "",
"blend": false,
"fields": null,
"methods": null,
"columns": null,
"label": "b",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"italic": false,
"bold": true,
"underline": false,
"labelWidth": 15,
"labelHeight": 26,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"zIndex": 0,
"level": 1
}
],
"connections": [
{
"id": "(a -> b)[0]",
"src": "a",
"srcArrow": "none",
"srcLabel": "",
"dst": "b",
"dstArrow": "triangle",
"dstLabel": "",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"label": "hello",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"italic": true,
"bold": false,
"underline": false,
"labelWidth": 31,
"labelHeight": 23,
"labelPosition": "INSIDE_MIDDLE_CENTER",
"labelPercentage": 0,
"route": [
{
"x": 57.5,
"y": 126
},
{
"x": 57.5,
"y": 166
},
{
"x": 57.5,
"y": 186
},
{
"x": 57.5,
"y": 226
}
],
"isCurve": true,
"animated": false,
"tooltip": "",
"icon": null,
"zIndex": 0
}
]
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 277 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 268 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 301 KiB

After

Width:  |  Height:  |  Size: 333 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 324 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 309 KiB

After

Width:  |  Height:  |  Size: 340 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 331 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 229 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 115 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 106 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 387 KiB

After

Width:  |  Height:  |  Size: 419 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 419 KiB

View file

@ -14,6 +14,8 @@ import (
"oss.terrastruct.com/d2/d2renderers/d2fonts"
"oss.terrastruct.com/d2/d2renderers/d2svg"
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/d2themes"
"oss.terrastruct.com/d2/lib/color"
"oss.terrastruct.com/d2/lib/textmeasure"
"oss.terrastruct.com/util-go/go2"
)
@ -48,8 +50,8 @@ const (
)
var viewboxRegex = regexp.MustCompile(`viewBox=\"([0-9\- ]+)\"`)
var widthRegex = regexp.MustCompile(`width=\"([0-9]+)\"`)
var heightRegex = regexp.MustCompile(`height=\"([0-9]+)\"`)
var widthRegex = regexp.MustCompile(`width=\"([.0-9]+)\"`)
var heightRegex = regexp.MustCompile(`height=\"([.0-9]+)\"`)
func Append(diagram *d2target.Diagram, ruler *textmeasure.Ruler, in []byte) []byte {
svg := string(in)
@ -68,9 +70,13 @@ func Append(diagram *d2target.Diagram, ruler *textmeasure.Ruler, in []byte) []by
viewboxHeight, _ := strconv.Atoi(viewboxSlice[3])
tl, br := diagram.BoundingBox()
seperator := fmt.Sprintf(`<line x1="%d" y1="%d" x2="%d" y2="%d" stroke="#0A0F25" />`,
tl.X-PAD_SIDES, br.Y+PAD_TOP, go2.IntMax(w, br.X)+PAD_SIDES, br.Y+PAD_TOP)
appendix = seperator + appendix
separatorEl := d2themes.NewThemableElement("line")
separatorEl.X1 = float64(tl.X - PAD_SIDES)
separatorEl.Y1 = float64(br.Y + PAD_TOP)
separatorEl.X2 = float64(go2.IntMax(w, br.X) + PAD_SIDES)
separatorEl.Y2 = float64(br.Y + PAD_TOP)
separatorEl.Stroke = color.B2 // same as --color-border-muted in markdown
appendix = separatorEl.Render() + appendix
w -= viewboxPadLeft
w += PAD_SIDES * 2
@ -82,14 +88,16 @@ func Append(diagram *d2target.Diagram, ruler *textmeasure.Ruler, in []byte) []by
newViewbox := fmt.Sprintf(`viewBox="%s %s %s %s"`, viewboxSlice[0], viewboxSlice[1], strconv.Itoa(viewboxWidth), strconv.Itoa(viewboxHeight))
widthMatch := widthRegex.FindStringSubmatch(svg)
heightMatch := heightRegex.FindStringSubmatch(svg)
widthMatches := widthRegex.FindAllStringSubmatch(svg, 2)
heightMatches := heightRegex.FindAllStringSubmatch(svg, 2)
newWidth := fmt.Sprintf(`width="%s"`, strconv.Itoa(viewboxWidth))
newHeight := fmt.Sprintf(`height="%s"`, strconv.Itoa(viewboxHeight))
svg = strings.Replace(svg, viewboxMatch[0], newViewbox, 1)
svg = strings.Replace(svg, widthMatch[0], newWidth, 1)
svg = strings.Replace(svg, heightMatch[0], newHeight, 1)
for i := 0; i < 2; i++ {
svg = strings.Replace(svg, widthMatches[i][0], newWidth, 1)
svg = strings.Replace(svg, heightMatches[i][0], newHeight, 1)
}
if !strings.Contains(svg, `font-family: "font-regular"`) {
appendix += fmt.Sprintf(`<style type="text/css"><![CDATA[
@ -158,7 +166,7 @@ func generateAppendix(diagram *d2target.Diagram, ruler *textmeasure.Ruler, svg s
}
totalHeight += SPACER
return fmt.Sprintf(`<g x="%d" y="%d" width="%d" height="100%%">%s</g>
return fmt.Sprintf(`<g class="appendix" x="%d" y="%d" width="%d" height="100%%">%s</g>
`, tl.X, br.Y, (br.X - tl.X), strings.Join(lines, "\n")), maxWidth, totalHeight
}

View file

@ -82,6 +82,14 @@ payment processor behind the scenes: {
script: `x: { link: https://d2lang.com }
y: { link: https://terrastruct.com; tooltip: Gee, I feel kind of LIGHT in the head now,\nknowing I can't make my satellite dish PAYMENTS! }
x -> y
`,
},
{
name: "links dark",
themeID: 200,
script: `x: { link: https://d2lang.com }
y: { link: https://fosny.eu; tooltip: Gee, I feel kind of LIGHT in the head now,\nknowing I can't make my satellite dish PAYMENTS! }
x -> y
`,
},
}
@ -89,9 +97,10 @@ x -> y
}
type testCase struct {
name string
script string
skip bool
name string
themeID int64
script string
skip bool
}
func runa(t *testing.T, tcs []testCase) {
@ -119,9 +128,8 @@ func run(t *testing.T, tc testCase) {
}
diagram, _, err := d2lib.Compile(ctx, tc.script, &d2lib.CompileOptions{
Ruler: ruler,
ThemeID: 0,
Layout: d2dagrelayout.DefaultLayout,
Ruler: ruler,
Layout: d2dagrelayout.DefaultLayout,
})
if !tassert.Nil(t, err) {
return
@ -131,7 +139,8 @@ func run(t *testing.T, tc testCase) {
pathGotSVG := filepath.Join(dataPath, "sketch.got.svg")
svgBytes, err := d2svg.Render(diagram, &d2svg.RenderOpts{
Pad: d2svg.DEFAULT_PADDING,
Pad: d2svg.DEFAULT_PADDING,
ThemeID: tc.themeID,
})
assert.Success(t, err)
svgBytes = appendix.Append(diagram, ruler, svgBytes)

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 803 KiB

After

Width:  |  Height:  |  Size: 807 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 651 KiB

After

Width:  |  Height:  |  Size: 655 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 650 KiB

After

Width:  |  Height:  |  Size: 655 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 650 KiB

After

Width:  |  Height:  |  Size: 654 KiB

View file

@ -3,17 +3,21 @@ package d2svg
import (
"fmt"
"io"
"strings"
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/d2themes"
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/label"
"oss.terrastruct.com/d2/lib/svg"
)
func classHeader(shape d2target.Shape, box *geo.Box, text string, textWidth, textHeight, fontSize float64) string {
str := fmt.Sprintf(`<rect class="class_header" x="%f" y="%f" width="%f" height="%f" fill="%s" />`,
box.TopLeft.X, box.TopLeft.Y, box.Width, box.Height, shape.Fill)
rectEl := d2themes.NewThemableElement("rect")
rectEl.X, rectEl.Y = box.TopLeft.X, box.TopLeft.Y
rectEl.Width, rectEl.Height = box.Width, box.Height
rectEl.Fill = shape.Fill
rectEl.ClassName = "class_header"
str := rectEl.Render()
if text != "" {
tl := label.InsideMiddleCenter.GetPointOnBox(
@ -23,17 +27,16 @@ func classHeader(shape d2target.Shape, box *geo.Box, text string, textWidth, tex
textHeight,
)
str += fmt.Sprintf(`<text class="%s" x="%f" y="%f" style="%s">%s</text>`,
"text-mono",
tl.X+textWidth/2,
tl.Y+textHeight*3/4,
fmt.Sprintf(`text-anchor:%s;font-size:%vpx;fill:%s`,
"middle",
4+fontSize,
shape.Stroke,
),
svg.EscapeText(text),
textEl := d2themes.NewThemableElement("text")
textEl.X = tl.X + textWidth/2
textEl.Y = tl.Y + textHeight*3/4
textEl.Fill = shape.Stroke
textEl.ClassName = "text-mono"
textEl.Style = fmt.Sprintf(`text-anchor:%s;font-size:%vpx;`,
"middle", 4+fontSize,
)
textEl.Content = svg.EscapeText(text)
str += textEl.Render()
}
return str
}
@ -54,33 +57,39 @@ func classRow(shape d2target.Shape, box *geo.Box, prefix, nameText, typeText str
fontSize,
)
return strings.Join([]string{
fmt.Sprintf(`<text class="text-mono" x="%f" y="%f" style="%s">%s</text>`,
prefixTL.X,
prefixTL.Y+fontSize*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s", "start", fontSize, shape.PrimaryAccentColor),
prefix,
),
textEl := d2themes.NewThemableElement("text")
textEl.X = prefixTL.X
textEl.Y = prefixTL.Y + fontSize*3/4
textEl.Fill = shape.PrimaryAccentColor
textEl.ClassName = "text-mono"
textEl.Style = fmt.Sprintf("text-anchor:%s;font-size:%vpx", "start", fontSize)
textEl.Content = prefix
out := textEl.Render()
fmt.Sprintf(`<text class="text-mono" x="%f" y="%f" style="%s">%s</text>`,
prefixTL.X+d2target.PrefixWidth,
prefixTL.Y+fontSize*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s", "start", fontSize, shape.Fill),
svg.EscapeText(nameText),
),
textEl.X = prefixTL.X + d2target.PrefixWidth
textEl.Fill = shape.Fill
textEl.Content = svg.EscapeText(nameText)
out += textEl.Render()
fmt.Sprintf(`<text class="text-mono" x="%f" y="%f" style="%s">%s</text>`,
typeTR.X,
typeTR.Y+fontSize*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s", "end", fontSize, shape.SecondaryAccentColor),
svg.EscapeText(typeText),
),
}, "\n")
textEl.X = typeTR.X
textEl.Y = typeTR.Y + fontSize*3/4
textEl.Fill = shape.SecondaryAccentColor
textEl.Style = fmt.Sprintf("text-anchor:%s;font-size:%vpx", "end", fontSize)
textEl.Content = svg.EscapeText(typeText)
out += textEl.Render()
return out
}
func drawClass(writer io.Writer, targetShape d2target.Shape) {
fmt.Fprintf(writer, `<rect class="shape" x="%d" y="%d" width="%d" height="%d" style="%s"/>`,
targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, targetShape.CSSStyle())
el := d2themes.NewThemableElement("rect")
el.X = float64(targetShape.Pos.X)
el.Y = float64(targetShape.Pos.Y)
el.Width = float64(targetShape.Width)
el.Height = float64(targetShape.Height)
el.Fill, el.Stroke = d2themes.ShapeTheme(targetShape)
el.Style = targetShape.CSSStyle()
fmt.Fprint(writer, el.Render())
box := geo.NewBox(
geo.NewPoint(float64(targetShape.Pos.X), float64(targetShape.Pos.Y)),
@ -103,10 +112,12 @@ func drawClass(writer io.Writer, targetShape d2target.Shape) {
rowBox.TopLeft.Y += rowHeight
}
fmt.Fprintf(writer, `<line x1="%f" y1="%f" x2="%f" y2="%f" style="%s" />`,
rowBox.TopLeft.X, rowBox.TopLeft.Y,
rowBox.TopLeft.X+rowBox.Width, rowBox.TopLeft.Y,
fmt.Sprintf("stroke-width:1;stroke:%v", targetShape.Fill))
lineEl := d2themes.NewThemableElement("line")
lineEl.X1, lineEl.Y1 = rowBox.TopLeft.X, rowBox.TopLeft.Y
lineEl.X2, lineEl.Y2 = rowBox.TopLeft.X+rowBox.Width, rowBox.TopLeft.Y
lineEl.Stroke = targetShape.Fill
lineEl.Style = "stroke-width:1"
fmt.Fprint(writer, lineEl.Render())
for _, m := range targetShape.Methods {
fmt.Fprint(writer,

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,441 @@
package dark_theme_test
import (
"context"
"encoding/xml"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"cdr.dev/slog"
tassert "github.com/stretchr/testify/assert"
"oss.terrastruct.com/util-go/assert"
"oss.terrastruct.com/util-go/diff"
"oss.terrastruct.com/util-go/go2"
"oss.terrastruct.com/d2/d2layouts/d2dagrelayout"
"oss.terrastruct.com/d2/d2lib"
"oss.terrastruct.com/d2/d2renderers/d2fonts"
"oss.terrastruct.com/d2/d2renderers/d2svg"
"oss.terrastruct.com/d2/lib/log"
"oss.terrastruct.com/d2/lib/textmeasure"
)
func TestDarkTheme(t *testing.T) {
t.Parallel()
tcs := []testCase{
{
name: "basic",
script: `a -> b
`,
},
{
name: "child to child",
script: `winter.snow -> summer.sun
`,
},
{
name: "animated",
script: `winter.snow -> summer.sun -> trees -> winter.snow: { style.animated: true }
`,
},
{
name: "connection label",
script: `a -> b: hello
`,
},
{
name: "twitter",
script: `timeline mixer: "" {
explanation: |md
## **Timeline mixer**
- Inject ads, who-to-follow, onboarding
- Conversation module
- Cursoring,pagination
- Tweat deduplication
- Served data logging
|
}
People discovery: "People discovery \nservice"
admixer: Ad mixer {
style.fill: "#cba6f7"
style.font-color: "#000000"
}
onboarding service: "Onboarding \nservice"
timeline mixer -> People discovery
timeline mixer -> onboarding service
timeline mixer -> admixer
container0: "" {
graphql
comment
tlsapi
}
container0.graphql: GraphQL\nFederated Strato Column {
shape: image
icon: https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/GraphQL_Logo.svg/1200px-GraphQL_Logo.svg.png
}
container0.comment: |md
## Tweet/user content hydration, visibility filtering
|
container0.tlsapi: TLS-API (being deprecated)
container0.graphql -> timeline mixer
timeline mixer <- container0.tlsapi
twitter fe: "Twitter Frontend " {
icon: https://icons.terrastruct.com/social/013-twitter-1.svg
shape: image
}
twitter fe -> container0.graphql: iPhone web
twitter fe -> container0.tlsapi: HTTP Android
web: Web {
icon: https://icons.terrastruct.com/azure/Web%20Service%20Color/App%20Service%20Domains.svg
shape: image
}
Iphone: {
icon: 'https://ss7.vzw.com/is/image/VerizonWireless/apple-iphone-12-64gb-purple-53017-mjn13ll-a?$device-lg$'
shape: image
}
Android: {
icon: https://cdn4.iconfinder.com/data/icons/smart-phones-technologies/512/android-phone.png
shape: image
}
web -> twitter fe
timeline scorer: "Timeline\nScorer" {
style.fill: "#fab387"
style.font-color: "#000000"
}
home ranker: Home Ranker
timeline service: Timeline Service
timeline mixer -> timeline scorer: Thrift RPC
timeline mixer -> home ranker: {
style.stroke-dash: 4
style.stroke: "#000E3D"
}
timeline mixer -> timeline service
home mixer: Home mixer {
# style.fill: "#c1a2f3"
}
container0.graphql -> home mixer: {
style.stroke-dash: 4
style.stroke: "#000E3D"
}
home mixer -> timeline scorer
home mixer -> home ranker: {
style.stroke-dash: 4
style.stroke: "#000E3D"
}
home mixer -> timeline service
manhattan 2: Manhattan
gizmoduck: Gizmoduck
socialgraph: Social graph
tweetypie: Tweety Pie
home mixer -> manhattan 2
home mixer -> gizmoduck
home mixer -> socialgraph
home mixer -> tweetypie
Iphone -> twitter fe
Android -> twitter fe
prediction service2: Prediction Service {
shape: image
icon: https://cdn-icons-png.flaticon.com/512/6461/6461819.png
}
home scorer: Home Scorer {
style.fill: "#eba0ac"
style.font-color: "#000000"
}
manhattan: Manhattan
memcache: Memcache {
icon: https://d1q6f0aelx0por.cloudfront.net/product-logos/de041504-0ddb-43f6-b89e-fe04403cca8d-memcached.png
}
fetch: Fetch {
style.multiple: true
shape: step
}
feature: Feature {
style.multiple: true
shape: step
}
scoring: Scoring {
style.multiple: true
shape: step
}
fetch -> feature
feature -> scoring
prediction service: Prediction Service {
shape: image
icon: https://cdn-icons-png.flaticon.com/512/6461/6461819.png
}
scoring -> prediction service
fetch -> container2.crmixer
home scorer -> manhattan: ""
home scorer -> memcache: ""
home scorer -> prediction service2
home ranker -> home scorer
home ranker -> container2.crmixer: Candidate Fetch
container2: "" {
style.stroke: "#b4befe"
style.fill: "#000000"
crmixer: CrMixer {
style.fill: "#11111b"
style.font-color: "#cdd6f4"
}
earlybird: EarlyBird
utag: Utag
space: Space
communities: Communities
}
etc: ...etc
home scorer -> etc: Feature Hydration
feature -> manhattan
feature -> memcache
feature -> etc: Candidate sources
`,
},
{
name: "all_shapes",
script: `
rectangle: {shape: "rectangle"}
square: {shape: "square"}
page: {shape: "page"}
parallelogram: {shape: "parallelogram"}
document: {shape: "document"}
cylinder: {shape: "cylinder"}
queue: {shape: "queue"}
package: {shape: "package"}
step: {shape: "step"}
callout: {shape: "callout"}
stored_data: {shape: "stored_data"}
person: {shape: "person"}
diamond: {shape: "diamond"}
oval: {shape: "oval"}
circle: {shape: "circle"}
hexagon: {shape: "hexagon"}
cloud: {shape: "cloud"}
rectangle -> square -> page
parallelogram -> document -> cylinder
queue -> package -> step
callout -> stored_data -> person
diamond -> oval -> circle
hexagon -> cloud
`,
},
{
name: "sql_tables",
script: `users: {
shape: sql_table
id: int
name: string
email: string
password: string
last_login: datetime
}
products: {
shape: sql_table
id: int
price: decimal
sku: string
name: string
}
orders: {
shape: sql_table
id: int
user_id: int
product_id: int
}
shipments: {
shape: sql_table
id: int
order_id: int
tracking_number: string {constraint: primary_key}
status: string
}
users.id <-> orders.user_id
products.id <-> orders.product_id
shipments.order_id <-> orders.id`,
},
{
name: "class",
script: `manager: BatchManager {
shape: class
-num: int
-timeout: int
-pid
+getStatus(): Enum
+getJobs(): "Job[]"
+setTimeout(seconds int)
}
`,
},
{
name: "arrowheads",
script: `
a: ""
b: ""
a.1 -- b.1: none
a.2 <-> b.2: arrow {
source-arrowhead.shape: arrow
target-arrowhead.shape: arrow
}
a.3 <-> b.3: triangle {
source-arrowhead.shape: triangle
target-arrowhead.shape: triangle
}
a.4 <-> b.4: diamond {
source-arrowhead.shape: diamond
target-arrowhead.shape: diamond
}
a.5 <-> b.5: diamond filled {
source-arrowhead: {
shape: diamond
style.filled: true
}
target-arrowhead: {
shape: diamond
style.filled: true
}
}
a.6 <-> b.6: cf-many {
source-arrowhead.shape: cf-many
target-arrowhead.shape: cf-many
}
a.7 <-> b.7: cf-many-required {
source-arrowhead.shape: cf-many-required
target-arrowhead.shape: cf-many-required
}
a.8 <-> b.8: cf-one {
source-arrowhead.shape: cf-one
target-arrowhead.shape: cf-one
}
a.9 <-> b.9: cf-one-required {
source-arrowhead.shape: cf-one-required
target-arrowhead.shape: cf-one-required
}
`,
},
{
name: "opacity",
script: `x.style.opacity: 0.4
y: |md
linux: because a PC is a terrible thing to waste
| {
style.opacity: 0.4
}
x -> a: {
label: You don't have to know how the computer works,\njust how to work the computer.
style.opacity: 0.4
}
users: {
shape: sql_table
last_login: datetime
style.opacity: 0.4
}
`,
},
{
name: "overlay",
script: `bright: {
style.stroke: "#000"
style.font-color: "#000"
style.fill: "#fff"
}
normal: {
style.stroke: "#000"
style.font-color: "#000"
style.fill: "#ccc"
}
dark: {
style.stroke: "#000"
style.font-color: "#fff"
style.fill: "#555"
}
darker: {
style.stroke: "#000"
style.font-color: "#fff"
style.fill: "#000"
}
`,
},
}
runa(t, tcs)
}
type testCase struct {
name string
script string
skip bool
}
func runa(t *testing.T, tcs []testCase) {
for _, tc := range tcs {
tc := tc
t.Run(tc.name, func(t *testing.T) {
if tc.skip {
t.Skip()
}
t.Parallel()
run(t, tc)
})
}
}
func run(t *testing.T, tc testCase) {
ctx := context.Background()
ctx = log.WithTB(ctx, t, nil)
ctx = log.Leveled(ctx, slog.LevelDebug)
ruler, err := textmeasure.NewRuler()
if !tassert.Nil(t, err) {
return
}
diagram, _, err := d2lib.Compile(ctx, tc.script, &d2lib.CompileOptions{
Ruler: ruler,
Layout: d2dagrelayout.DefaultLayout,
FontFamily: go2.Pointer(d2fonts.HandDrawn),
})
if !tassert.Nil(t, err) {
return
}
dataPath := filepath.Join("testdata", strings.TrimPrefix(t.Name(), "TestDarkTheme/"))
pathGotSVG := filepath.Join(dataPath, "dark_theme.got.svg")
svgBytes, err := d2svg.Render(diagram, &d2svg.RenderOpts{
Pad: d2svg.DEFAULT_PADDING,
ThemeID: 200,
})
assert.Success(t, err)
err = os.MkdirAll(dataPath, 0755)
assert.Success(t, err)
err = ioutil.WriteFile(pathGotSVG, svgBytes, 0600)
assert.Success(t, err)
defer os.Remove(pathGotSVG)
var xmlParsed interface{}
err = xml.Unmarshal(svgBytes, &xmlParsed)
assert.Success(t, err)
err = diff.Testdata(filepath.Join(dataPath, "dark_theme"), ".svg", svgBytes)
assert.Success(t, err)
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 196 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 240 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 253 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 188 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 238 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 188 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 238 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 299 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 188 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 64 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 320 KiB

View file

@ -20,29 +20,14 @@
tab-size: 4;
}
/* based on https://github.com/sindresorhus/github-markdown-css */
.md {
color-scheme: light;
--color-fg-default: #24292f;
--color-fg-muted: #57606a;
--color-fg-subtle: #6e7781;
--color-canvas-default: #ffffff;
--color-canvas-subtle: #f6f8fa;
--color-border-default: #d0d7de;
--color-border-muted: hsla(210, 18%, 87%, 1);
--color-neutral-muted: rgba(175, 184, 193, 0.2);
--color-accent-fg: #0969da;
--color-accent-emphasis: #0969da;
--color-attention-subtle: #fff8c5;
--color-danger-fg: #cf222e;
}
/* variables are provided in d2renderers/d2svg/d2svg.go */
.md {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
margin: 0;
color: var(--color-fg-default);
background-color: var(--color-canvas-default);
background-color: transparent; /* we don't want to define the background color */
font-family: "font-regular";
font-size: 16px;
line-height: 1.5;

View file

@ -1,4 +0,0 @@
.sketch-overlay {
fill: url(#streaks);
mix-blend-mode: overlay;
}

View file

@ -3,9 +3,9 @@ package d2svg
import (
"fmt"
"io"
"strings"
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/d2themes"
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/label"
"oss.terrastruct.com/d2/lib/svg"
@ -13,8 +13,12 @@ import (
)
func tableHeader(shape d2target.Shape, box *geo.Box, text string, textWidth, textHeight, fontSize float64) string {
str := fmt.Sprintf(`<rect class="class_header" x="%f" y="%f" width="%f" height="%f" fill="%s" />`,
box.TopLeft.X, box.TopLeft.Y, box.Width, box.Height, shape.Fill)
rectEl := d2themes.NewThemableElement("rect")
rectEl.X, rectEl.Y = box.TopLeft.X, box.TopLeft.Y
rectEl.Width, rectEl.Height = box.Width, box.Height
rectEl.Fill = shape.Fill
rectEl.ClassName = "class_header"
str := rectEl.Render()
if text != "" {
tl := label.InsideMiddleLeft.GetPointOnBox(
@ -24,17 +28,16 @@ func tableHeader(shape d2target.Shape, box *geo.Box, text string, textWidth, tex
textHeight,
)
str += fmt.Sprintf(`<text class="%s" x="%f" y="%f" style="%s">%s</text>`,
"text",
tl.X,
tl.Y+textHeight*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s",
"start",
4+fontSize,
shape.Stroke,
),
svg.EscapeText(text),
textEl := d2themes.NewThemableElement("text")
textEl.X = tl.X
textEl.Y = tl.Y + textHeight*3/4
textEl.Fill = shape.Stroke
textEl.ClassName = "text"
textEl.Style = fmt.Sprintf("text-anchor:%s;font-size:%vpx",
"start", 4+fontSize,
)
textEl.Content = svg.EscapeText(text)
str += textEl.Render()
}
return str
}
@ -55,33 +58,40 @@ func tableRow(shape d2target.Shape, box *geo.Box, nameText, typeText, constraint
fontSize,
)
return strings.Join([]string{
fmt.Sprintf(`<text class="text" x="%f" y="%f" style="%s">%s</text>`,
nameTL.X,
nameTL.Y+fontSize*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s", "start", fontSize, shape.PrimaryAccentColor),
svg.EscapeText(nameText),
),
textEl := d2themes.NewThemableElement("text")
textEl.X = nameTL.X
textEl.Y = nameTL.Y + fontSize*3/4
textEl.Fill = shape.PrimaryAccentColor
textEl.ClassName = "text"
textEl.Style = fmt.Sprintf("text-anchor:%s;font-size:%vpx", "start", fontSize)
textEl.Content = svg.EscapeText(nameText)
out := textEl.Render()
fmt.Sprintf(`<text class="text" x="%f" y="%f" style="%s">%s</text>`,
nameTL.X+longestNameWidth+2*d2target.NamePadding,
nameTL.Y+fontSize*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s", "start", fontSize, shape.NeutralAccentColor),
svg.EscapeText(typeText),
),
textEl.X = nameTL.X + longestNameWidth + 2*d2target.NamePadding
textEl.Fill = shape.NeutralAccentColor
textEl.Content = svg.EscapeText(typeText)
out += textEl.Render()
fmt.Sprintf(`<text class="text" x="%f" y="%f" style="%s">%s</text>`,
constraintTR.X,
constraintTR.Y+fontSize*3/4,
fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s;letter-spacing:2px;", "end", fontSize, shape.SecondaryAccentColor),
constraintText,
),
}, "\n")
textEl.X = constraintTR.X
textEl.Y = constraintTR.Y + fontSize*3/4
textEl.Fill = shape.SecondaryAccentColor
textEl.Style = fmt.Sprintf("text-anchor:%s;font-size:%vpx;letter-spacing:2px", "end", fontSize)
textEl.Content = constraintText
out += textEl.Render()
return out
}
func drawTable(writer io.Writer, targetShape d2target.Shape) {
fmt.Fprintf(writer, `<rect class="shape" x="%d" y="%d" width="%d" height="%d" style="%s"/>`,
targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, targetShape.CSSStyle())
rectEl := d2themes.NewThemableElement("rect")
rectEl.X = float64(targetShape.Pos.X)
rectEl.Y = float64(targetShape.Pos.Y)
rectEl.Width = float64(targetShape.Width)
rectEl.Height = float64(targetShape.Height)
rectEl.Fill, rectEl.Stroke = d2themes.ShapeTheme(targetShape)
rectEl.ClassName = "shape"
rectEl.Style = targetShape.CSSStyle()
fmt.Fprint(writer, rectEl.Render())
box := geo.NewBox(
geo.NewPoint(float64(targetShape.Pos.X), float64(targetShape.Pos.Y)),
@ -108,10 +118,12 @@ func drawTable(writer io.Writer, targetShape d2target.Shape) {
tableRow(targetShape, rowBox, f.Name.Label, f.Type.Label, f.ConstraintAbbr(), float64(targetShape.FontSize), float64(longestNameWidth)),
)
rowBox.TopLeft.Y += rowHeight
fmt.Fprintf(writer, `<line x1="%f" y1="%f" x2="%f" y2="%f" style="stroke-width:2;stroke:%s" />`,
rowBox.TopLeft.X, rowBox.TopLeft.Y,
rowBox.TopLeft.X+rowBox.Width, rowBox.TopLeft.Y,
targetShape.Fill,
)
lineEl := d2themes.NewThemableElement("line")
lineEl.X1, lineEl.Y1 = rowBox.TopLeft.X, rowBox.TopLeft.Y
lineEl.X2, lineEl.Y2 = rowBox.TopLeft.X+rowBox.Width, rowBox.TopLeft.Y
lineEl.Stroke = targetShape.Fill
lineEl.Style = "stroke-width:2"
fmt.Fprint(writer, lineEl.Render())
}
}

View file

@ -11,7 +11,7 @@ import (
"oss.terrastruct.com/util-go/go2"
"oss.terrastruct.com/d2/d2renderers/d2fonts"
"oss.terrastruct.com/d2/d2themes"
"oss.terrastruct.com/d2/lib/color"
"oss.terrastruct.com/d2/lib/geo"
"oss.terrastruct.com/d2/lib/label"
"oss.terrastruct.com/d2/lib/shape"
@ -184,16 +184,6 @@ type Shape struct {
func (s Shape) CSSStyle() string {
out := ""
if s.Type == ShapeSQLTable || s.Type == ShapeClass {
// Fill is used for header fill in these types
// This fill property is just background of rows
out += fmt.Sprintf(`fill:%s;`, s.Stroke)
// Stroke (border) of these shapes should match the header fill
out += fmt.Sprintf(`stroke:%s;`, s.Fill)
} else {
out += fmt.Sprintf(`fill:%s;`, s.Fill)
out += fmt.Sprintf(`stroke:%s;`, s.Stroke)
}
out += fmt.Sprintf(`stroke-width:%d;`, s.StrokeWidth)
if s.StrokeDash != 0 {
dashSize, gapSize := svg.GetStrokeDashAttributes(float64(s.StrokeWidth), s.StrokeDash)
@ -299,7 +289,6 @@ func BaseConnection() *Connection {
func (c Connection) CSSStyle() string {
out := ""
out += fmt.Sprintf(`stroke:%s;`, c.Stroke)
out += fmt.Sprintf(`stroke-width:%d;`, c.StrokeWidth)
strokeDash := c.StrokeDash
if strokeDash == 0 && c.Animated {
@ -495,11 +484,11 @@ func NewTextDimensions(w, h int) *TextDimensions {
return &TextDimensions{Width: w, Height: h}
}
func (text MText) GetColor(theme *d2themes.Theme, isItalic bool) string {
func (text MText) GetColor(isItalic bool) string {
if isItalic {
return theme.Colors.Neutrals.N2
return color.N2
}
return theme.Colors.Neutrals.N1
return color.N1
}
var DSL_SHAPE_TO_SHAPE_TYPE = map[string]string{

19
d2themes/common.go Normal file
View file

@ -0,0 +1,19 @@
package d2themes
import (
"oss.terrastruct.com/d2/d2target"
)
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
}

View file

@ -58,3 +58,13 @@ var WarmNeutral = Neutral{
N6: "#ECEBEB",
N7: "#FFFFFF",
}
var DarkNeutral = Neutral{
N1: "#CDD6F4",
N2: "#BAC2DE",
N3: "#A6ADC8",
N4: "#585B70",
N5: "#45475A",
N6: "#313244",
N7: "#1E1E2E",
}

View file

@ -7,7 +7,7 @@ import (
"oss.terrastruct.com/d2/d2themes"
)
var Catalog = []d2themes.Theme{
var LightCatalog = []d2themes.Theme{
NeutralDefault,
NeutralGrey,
FlagshipTerrastruct,
@ -24,8 +24,18 @@ var Catalog = []d2themes.Theme{
ButteredToast,
}
var DarkCatalog = []d2themes.Theme{
DarkMauve,
}
func Find(id int64) d2themes.Theme {
for _, theme := range Catalog {
for _, theme := range LightCatalog {
if theme.ID == id {
return theme
}
}
for _, theme := range DarkCatalog {
if theme.ID == id {
return theme
}
@ -36,8 +46,16 @@ func Find(id int64) d2themes.Theme {
func CLIString() string {
var s strings.Builder
for _, t := range Catalog {
s.WriteString("Light:\n")
for _, t := range LightCatalog {
s.WriteString(fmt.Sprintf("- %s: %d\n", t.Name, t.ID))
}
s.WriteString("Dark:\n")
for _, t := range DarkCatalog {
s.WriteString(fmt.Sprintf("- %s: %d\n", t.Name, t.ID))
}
return s.String()
}

View file

@ -0,0 +1,25 @@
package d2themescatalog
import "oss.terrastruct.com/d2/d2themes"
var DarkMauve = d2themes.Theme{
ID: 200,
Name: "Dark Mauve",
Colors: d2themes.ColorPalette{
Neutrals: d2themes.DarkNeutral,
B1: "#CBA6f7",
B2: "#CBA6f7",
B3: "#6C7086",
B4: "#585B70",
B5: "#45475A",
B6: "#313244",
AA2: "#f38BA8",
AA4: "#45475A",
AA5: "#313244",
AB4: "#45475A",
AB5: "#313244",
},
}

197
d2themes/element.go Normal file
View file

@ -0,0 +1,197 @@
package d2themes
import (
"fmt"
"math"
"oss.terrastruct.com/d2/lib/color"
)
// ThemableElement is a helper class for creating new XML elements.
// This should be preferred over formatting and must be used
// whenever Fill, Stroke, BackgroundColor or Color contains a color from a theme.
// i.e. N[1-7] | B[1-6] | AA[245] | AB[45]
type ThemableElement struct {
tag string
X float64
X1 float64
X2 float64
Y float64
Y1 float64
Y2 float64
Width float64
Height float64
R float64
Rx float64
Ry float64
Cx float64
Cy float64
D string
Mask string
Points string
Transform string
Href string
Xmlns string
Fill string
Stroke string
BackgroundColor string
Color string
ClassName string
Style string
Attributes string
Content string
}
func NewThemableElement(tag string) *ThemableElement {
xmlns := ""
if tag == "div" {
xmlns = "http://www.w3.org/1999/xhtml"
}
return &ThemableElement{
tag,
math.MaxFloat64,
math.MaxFloat64,
math.MaxFloat64,
math.MaxFloat64,
math.MaxFloat64,
math.MaxFloat64,
math.MaxFloat64,
math.MaxFloat64,
math.MaxFloat64,
math.MaxFloat64,
math.MaxFloat64,
math.MaxFloat64,
math.MaxFloat64,
"",
"",
"",
"",
"",
xmlns,
color.Empty,
color.Empty,
color.Empty,
color.Empty,
"",
"",
"",
"",
}
}
func (el *ThemableElement) SetTranslate(x, y float64) {
el.Transform = fmt.Sprintf("translate(%f %f)", x, y)
}
func (el *ThemableElement) SetMaskUrl(url string) {
el.Mask = fmt.Sprintf("url(#%s)", url)
}
func (el *ThemableElement) Render() string {
out := "<" + el.tag
if el.X != math.MaxFloat64 {
out += fmt.Sprintf(` x="%f"`, el.X)
}
if el.X1 != math.MaxFloat64 {
out += fmt.Sprintf(` x1="%f"`, el.X1)
}
if el.X2 != math.MaxFloat64 {
out += fmt.Sprintf(` x2="%f"`, el.X2)
}
if el.Y != math.MaxFloat64 {
out += fmt.Sprintf(` y="%f"`, el.Y)
}
if el.Y1 != math.MaxFloat64 {
out += fmt.Sprintf(` y1="%f"`, el.Y1)
}
if el.Y2 != math.MaxFloat64 {
out += fmt.Sprintf(` y2="%f"`, el.Y2)
}
if el.Width != math.MaxFloat64 {
out += fmt.Sprintf(` width="%f"`, el.Width)
}
if el.Height != math.MaxFloat64 {
out += fmt.Sprintf(` height="%f"`, el.Height)
}
if el.R != math.MaxFloat64 {
out += fmt.Sprintf(` r="%f"`, el.R)
}
if el.Rx != math.MaxFloat64 {
out += fmt.Sprintf(` rx="%f"`, el.Rx)
}
if el.Ry != math.MaxFloat64 {
out += fmt.Sprintf(` ry="%f"`, el.Ry)
}
if el.Cx != math.MaxFloat64 {
out += fmt.Sprintf(` cx="%f"`, el.Cx)
}
if el.Cy != math.MaxFloat64 {
out += fmt.Sprintf(` cy="%f"`, el.Cy)
}
if len(el.D) > 0 {
out += fmt.Sprintf(` d="%s"`, el.D)
}
if len(el.Mask) > 0 {
out += fmt.Sprintf(` mask="%s"`, el.Mask)
}
if len(el.Points) > 0 {
out += fmt.Sprintf(` points="%s"`, el.Points)
}
if len(el.Transform) > 0 {
out += fmt.Sprintf(` transform="%s"`, el.Transform)
}
if len(el.Href) > 0 {
out += fmt.Sprintf(` href="%s"`, el.Href)
}
if len(el.Xmlns) > 0 {
out += fmt.Sprintf(` xmlns="%s"`, el.Xmlns)
}
class := el.ClassName
style := el.Style
// Add class {property}-{theme color} if the color is from a theme, set the property otherwise
if color.IsThemeColor(el.Stroke) {
class += fmt.Sprintf(" stroke-%s", el.Stroke)
} else if len(el.Stroke) > 0 {
out += fmt.Sprintf(` stroke="%s"`, el.Stroke)
}
if color.IsThemeColor(el.Fill) {
class += fmt.Sprintf(" fill-%s", el.Fill)
} else if len(el.Fill) > 0 {
out += fmt.Sprintf(` fill="%s"`, el.Fill)
}
if color.IsThemeColor(el.BackgroundColor) {
class += fmt.Sprintf(" background-color-%s", el.BackgroundColor)
} else if len(el.BackgroundColor) > 0 {
out += fmt.Sprintf(` background-color="%s"`, el.BackgroundColor)
}
if color.IsThemeColor(el.Color) {
class += fmt.Sprintf(" color-%s", el.Color)
} else if len(el.Color) > 0 {
out += fmt.Sprintf(` color="%s"`, el.Color)
}
if len(class) > 0 {
out += fmt.Sprintf(` class="%s"`, class)
}
if len(style) > 0 {
out += fmt.Sprintf(` style="%s"`, style)
}
if len(el.Attributes) > 0 {
out += fmt.Sprintf(` %s`, el.Attributes)
}
if len(el.Content) > 0 {
return fmt.Sprintf("%s>%s</%s>", out, el.Content, el.tag)
}
return out + " />"
}

View file

@ -0,0 +1,34 @@
package d2themes
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.ClassName += 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.ClassName += fmt.Sprintf(" sketch-overlay-%s", lc) // e.g. sketch-overlay-dark
}
return o.el.Render(), nil
}

View file

@ -20,12 +20,12 @@ func main() {
return d2dagrelayout.Layout(ctx, g, nil)
}
diagram, _, _ := d2lib.Compile(context.Background(), "x -> y", &d2lib.CompileOptions{
Layout: defaultLayout,
Ruler: ruler,
ThemeID: d2themescatalog.GrapeSoda.ID,
Layout: defaultLayout,
Ruler: ruler,
})
out, _ := d2svg.Render(diagram, &d2svg.RenderOpts{
Pad: d2svg.DEFAULT_PADDING,
Pad: d2svg.DEFAULT_PADDING,
ThemeID: d2themescatalog.GrapeSoda.ID,
})
_ = ioutil.WriteFile(filepath.Join("out.svg"), out, 0600)
}

View file

@ -8,7 +8,6 @@ import (
"oss.terrastruct.com/d2/d2layouts/d2dagrelayout"
"oss.terrastruct.com/d2/d2lib"
"oss.terrastruct.com/d2/d2oracle"
"oss.terrastruct.com/d2/d2themes/d2themescatalog"
"oss.terrastruct.com/d2/lib/textmeasure"
)
@ -17,9 +16,8 @@ func main() {
// From one.go
ruler, _ := textmeasure.NewRuler()
_, graph, _ := d2lib.Compile(context.Background(), "x -> y", &d2lib.CompileOptions{
Layout: d2dagrelayout.DefaultLayout,
Ruler: ruler,
ThemeID: d2themescatalog.GrapeSoda.ID,
Layout: d2dagrelayout.DefaultLayout,
Ruler: ruler,
})
// Create a shape with the ID, "meow"

View file

@ -20,9 +20,10 @@ func main() {
ruler, _ := textmeasure.NewRuler()
_ = graph.SetDimensions(nil, ruler, nil)
_ = d2dagrelayout.Layout(context.Background(), graph, nil)
diagram, _ := d2exporter.Export(context.Background(), graph, d2themescatalog.NeutralDefault.ID, nil)
diagram, _ := d2exporter.Export(context.Background(), graph, nil)
out, _ := d2svg.Render(diagram, &d2svg.RenderOpts{
Pad: d2svg.DEFAULT_PADDING,
Pad: d2svg.DEFAULT_PADDING,
ThemeID: d2themescatalog.NeutralDefault.ID,
})
_ = ioutil.WriteFile(filepath.Join("out.svg"), out, 0600)
}

View file

@ -155,7 +155,6 @@ func run(t *testing.T, tc testCase) {
diagram, g, err := d2lib.Compile(ctx, tc.script, &d2lib.CompileOptions{
Ruler: ruler,
MeasuredTexts: tc.mtexts,
ThemeID: 0,
Layout: layout,
})
@ -197,7 +196,8 @@ func run(t *testing.T, tc testCase) {
pathGotSVG := filepath.Join(dataPath, "sketch.got.svg")
svgBytes, err := d2svg.Render(diagram, &d2svg.RenderOpts{
Pad: d2svg.DEFAULT_PADDING,
Pad: d2svg.DEFAULT_PADDING,
ThemeID: 0,
})
assert.Success(t, err)
err = os.MkdirAll(dataPath, 0755)

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#0A0F25",
"stroke": "#FFFFFF",
"fill": "N1",
"stroke": "N7",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -41,9 +41,9 @@
"labelHeight": 0,
"zIndex": 0,
"level": 1,
"primaryAccentColor": "#0D32B2",
"secondaryAccentColor": "#4A6FF3",
"neutralAccentColor": "#676C7E"
"primaryAccentColor": "B2",
"secondaryAccentColor": "AA2",
"neutralAccentColor": "N2"
}
],
"connections": []

View file

@ -1,11 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<svg
id="d2-svg"
style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="316" height="248" viewBox="-102 -102 316 248"><style type="text/css">
<![CDATA[
.shape {
<?xml version="1.0" encoding="utf-8"?><svg id="d2-svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="316" height="248" viewBox="-102 -102 316 248"><rect x="-102.000000" y="-102.000000" width="316.000000" height="248.000000" class=" fill-N7" /><style type="text/css"><![CDATA[]]></style><style type="text/css"><![CDATA[.shape {
shape-rendering: geometricPrecision;
stroke-linejoin: round;
}
@ -17,9 +10,7 @@ width="316" height="248" viewBox="-102 -102 316 248"><style type="text/css">
mix-blend-mode: multiply;
opacity: 0.5;
}
]]>
</style><script type="application/javascript"><![CDATA[window.addEventListener("DOMContentLoaded", () => {
.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:#EDF0FD;}.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:#EDF0FD;}.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:#EDF0FD;}.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:#EDF0FD;}.color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}]]></style><script type="application/javascript"><![CDATA[window.addEventListener("DOMContentLoaded", () => {
if (document.documentElement.getAttribute("id") !== "d2-svg") {
return;
}
@ -39,7 +30,7 @@ width="316" height="248" viewBox="-102 -102 316 248"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16);
}
});
]]></script><g id="a"><g class="shape" ><rect class="shape" x="0" y="0" width="112" height="44" style="fill:#FFFFFF;stroke:#0A0F25;stroke-width:2;"/><rect class="class_header" x="0.000000" y="0.000000" width="112.000000" height="44.000000" fill="#0A0F25" /><line x1="0.000000" y1="44.000000" x2="112.000000" y2="44.000000" style="stroke-width:1;stroke:#0A0F25" /></g></g><mask id="2019199647" maskUnits="userSpaceOnUse" x="-102" y="-102" width="316" height="248">
]]></script><g id="a"><g class="shape" ><rect x="0.000000" y="0.000000" width="112.000000" height="44.000000" class=" stroke-N1 fill-N7" style="stroke-width:2;" /><rect x="0.000000" y="0.000000" width="112.000000" height="44.000000" class="class_header fill-N1" /><line x1="0.000000" x2="112.000000" y1="44.000000" y2="44.000000" class=" stroke-N1" style="stroke-width:1" /></g></g><mask id="148127623" maskUnits="userSpaceOnUse" x="-102" y="-102" width="316" height="248">
<rect x="-102" y="-102" width="316" height="248" fill="white"></rect>
</mask><style type="text/css"><![CDATA[]]></style></svg>
</mask></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,

View file

@ -1,11 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<svg
id="d2-svg"
style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="304" height="304" viewBox="-102 -102 304 304"><style type="text/css">
<![CDATA[
.shape {
<?xml version="1.0" encoding="utf-8"?><svg id="d2-svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="304" height="304" viewBox="-102 -102 304 304"><rect x="-102.000000" y="-102.000000" width="304.000000" height="304.000000" class=" fill-N7" /><style type="text/css"><![CDATA[]]></style><style type="text/css"><![CDATA[.shape {
shape-rendering: geometricPrecision;
stroke-linejoin: round;
}
@ -17,9 +10,7 @@ width="304" height="304" viewBox="-102 -102 304 304"><style type="text/css">
mix-blend-mode: multiply;
opacity: 0.5;
}
]]>
</style><script type="application/javascript"><![CDATA[window.addEventListener("DOMContentLoaded", () => {
.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:#EDF0FD;}.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:#EDF0FD;}.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:#EDF0FD;}.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:#EDF0FD;}.color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}]]></style><script type="application/javascript"><![CDATA[window.addEventListener("DOMContentLoaded", () => {
if (document.documentElement.getAttribute("id") !== "d2-svg") {
return;
}
@ -39,7 +30,7 @@ width="304" height="304" viewBox="-102 -102 304 304"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16);
}
});
]]></script><g id="a"><g class="shape" ><rect x="0" y="0" width="100" height="100" style="fill:#F7F8FE;stroke:#0D32B2;stroke-width:2;" /></g></g><mask id="4175712569" maskUnits="userSpaceOnUse" x="-102" y="-102" width="304" height="304">
]]></script><g id="a"><g class="shape" ><rect x="0.000000" y="0.000000" width="100.000000" height="100.000000" class=" stroke-B1 fill-B6" style="stroke-width:2;" /></g></g><mask id="198791073" maskUnits="userSpaceOnUse" x="-102" y="-102" width="304" height="304">
<rect x="-102" y="-102" width="304" height="304" fill="white"></rect>
</mask><style type="text/css"><![CDATA[]]></style></svg>
</mask></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#0A0F25",
"stroke": "#FFFFFF",
"fill": "N1",
"stroke": "N7",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -41,9 +41,9 @@
"labelHeight": 0,
"zIndex": 0,
"level": 1,
"primaryAccentColor": "#0D32B2",
"secondaryAccentColor": "#4A6FF3",
"neutralAccentColor": "#676C7E"
"primaryAccentColor": "B2",
"secondaryAccentColor": "AA2",
"neutralAccentColor": "N2"
}
],
"connections": []

View file

@ -1,11 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<svg
id="d2-svg"
style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="254" height="216" viewBox="-102 -102 254 216"><style type="text/css">
<![CDATA[
.shape {
<?xml version="1.0" encoding="utf-8"?><svg id="d2-svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="254" height="216" viewBox="-102 -102 254 216"><rect x="-102.000000" y="-102.000000" width="254.000000" height="216.000000" class=" fill-N7" /><style type="text/css"><![CDATA[]]></style><style type="text/css"><![CDATA[.shape {
shape-rendering: geometricPrecision;
stroke-linejoin: round;
}
@ -17,9 +10,7 @@ width="254" height="216" viewBox="-102 -102 254 216"><style type="text/css">
mix-blend-mode: multiply;
opacity: 0.5;
}
]]>
</style><script type="application/javascript"><![CDATA[window.addEventListener("DOMContentLoaded", () => {
.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:#EDF0FD;}.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:#EDF0FD;}.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:#EDF0FD;}.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:#EDF0FD;}.color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}]]></style><script type="application/javascript"><![CDATA[window.addEventListener("DOMContentLoaded", () => {
if (document.documentElement.getAttribute("id") !== "d2-svg") {
return;
}
@ -39,7 +30,7 @@ width="254" height="216" viewBox="-102 -102 254 216"><style type="text/css">
svgEl.setAttribute("height", height * ratio - 16);
}
});
]]></script><g id="a"><g class="shape" ><rect class="shape" x="0" y="0" width="50" height="12" style="fill:#FFFFFF;stroke:#0A0F25;stroke-width:2;"/><rect class="class_header" x="0.000000" y="0.000000" width="50.000000" height="12.000000" fill="#0A0F25" /></g></g><mask id="1023975809" maskUnits="userSpaceOnUse" x="-102" y="-102" width="254" height="216">
]]></script><g id="a"><g class="shape" ><rect x="0.000000" y="0.000000" width="50.000000" height="12.000000" class="shape stroke-N1 fill-N7" style="stroke-width:2;" /><rect x="0.000000" y="0.000000" width="50.000000" height="12.000000" class="class_header fill-N1" /></g></g><mask id="2388684491" maskUnits="userSpaceOnUse" x="-102" y="-102" width="254" height="216">
<rect x="-102" y="-102" width="254" height="216" fill="white"></rect>
</mask><style type="text/css"><![CDATA[]]></style></svg>
</mask></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -56,8 +56,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -74,7 +74,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -97,8 +97,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -115,7 +115,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 326 KiB

After

Width:  |  Height:  |  Size: 330 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -56,8 +56,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -74,7 +74,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -97,8 +97,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -115,7 +115,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 326 KiB

After

Width:  |  Height:  |  Size: 330 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"stroke": "#0A0F25",
"fill": "N7",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "python",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -55,8 +55,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"stroke": "#0A0F25",
"fill": "N7",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
@ -73,7 +73,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "python",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -95,8 +95,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"stroke": "#0A0F25",
"fill": "N7",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
@ -113,7 +113,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "python",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 350 KiB

After

Width:  |  Height:  |  Size: 519 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"stroke": "#0A0F25",
"fill": "N7",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "python",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -55,8 +55,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"stroke": "#0A0F25",
"fill": "N7",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
@ -73,7 +73,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "python",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -95,8 +95,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#FFFFFF",
"stroke": "#0A0F25",
"fill": "N7",
"stroke": "N1",
"shadow": false,
"3d": false,
"multiple": false,
@ -113,7 +113,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "python",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 350 KiB

After

Width:  |  Height:  |  Size: 519 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -56,8 +56,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -74,7 +74,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -97,8 +97,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -115,7 +115,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -138,8 +138,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -156,7 +156,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -179,8 +179,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -197,7 +197,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -220,8 +220,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -238,7 +238,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -261,8 +261,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -279,7 +279,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -302,7 +302,7 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"fill": "B5",
"stroke": "red",
"shadow": false,
"3d": false,
@ -320,7 +320,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -343,8 +343,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -361,7 +361,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -384,8 +384,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -402,7 +402,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -425,8 +425,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -443,7 +443,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -466,8 +466,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -484,7 +484,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -507,8 +507,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -525,7 +525,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -548,8 +548,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -566,7 +566,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -589,8 +589,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -607,7 +607,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -630,8 +630,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -648,7 +648,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -671,8 +671,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -689,7 +689,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -712,8 +712,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -730,7 +730,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -753,8 +753,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -771,7 +771,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -794,8 +794,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -812,7 +812,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -835,8 +835,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -853,7 +853,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -876,8 +876,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -894,7 +894,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -917,8 +917,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -935,7 +935,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -958,8 +958,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -976,7 +976,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -999,8 +999,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -1017,7 +1017,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -1040,8 +1040,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -1058,7 +1058,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -1081,12 +1081,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -1165,12 +1165,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -1249,12 +1249,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -1333,12 +1333,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -1417,12 +1417,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -1501,12 +1501,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -1590,7 +1590,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -1657,12 +1657,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "1\n2\n3\n4",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 802 KiB

After

Width:  |  Height:  |  Size: 806 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -56,8 +56,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -74,7 +74,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -97,8 +97,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -115,7 +115,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -138,8 +138,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -156,7 +156,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -179,8 +179,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -197,7 +197,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -220,8 +220,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -238,7 +238,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -261,8 +261,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -279,7 +279,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -302,7 +302,7 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"fill": "B5",
"stroke": "red",
"shadow": false,
"3d": false,
@ -320,7 +320,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -343,8 +343,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -361,7 +361,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -384,8 +384,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -402,7 +402,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -425,8 +425,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -443,7 +443,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -466,8 +466,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -484,7 +484,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -507,8 +507,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -525,7 +525,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -548,8 +548,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -566,7 +566,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -589,8 +589,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -607,7 +607,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -630,8 +630,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -648,7 +648,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -671,8 +671,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -689,7 +689,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -712,8 +712,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -730,7 +730,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -753,8 +753,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -771,7 +771,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -794,8 +794,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -812,7 +812,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -835,8 +835,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -853,7 +853,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -876,8 +876,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -894,7 +894,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -917,8 +917,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -935,7 +935,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -958,8 +958,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -976,7 +976,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -999,8 +999,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -1017,7 +1017,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -1040,8 +1040,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -1058,7 +1058,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -1081,12 +1081,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -1120,12 +1120,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -1175,12 +1175,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -1222,12 +1222,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -1269,12 +1269,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -1308,12 +1308,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -1352,7 +1352,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -1386,12 +1386,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "1\n2\n3\n4",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 801 KiB

After

Width:  |  Height:  |  Size: 805 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -56,8 +56,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -74,7 +74,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -97,7 +97,7 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"fill": "B5",
"stroke": "white",
"shadow": false,
"3d": false,
@ -115,7 +115,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -138,8 +138,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -156,7 +156,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -179,8 +179,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -197,7 +197,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -220,8 +220,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -238,7 +238,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -309,12 +309,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -357,12 +357,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 794 KiB

After

Width:  |  Height:  |  Size: 798 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -56,8 +56,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -74,7 +74,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -97,7 +97,7 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"fill": "B5",
"stroke": "white",
"shadow": false,
"3d": false,
@ -115,7 +115,7 @@
"fontSize": 24,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -138,8 +138,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -156,7 +156,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -179,8 +179,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -197,7 +197,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -220,8 +220,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -238,7 +238,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -308,12 +308,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -347,12 +347,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 794 KiB

After

Width:  |  Height:  |  Size: 798 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -56,8 +56,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -74,7 +74,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -97,8 +97,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -115,7 +115,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -138,8 +138,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -156,7 +156,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -179,8 +179,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -197,7 +197,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -220,8 +220,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -238,7 +238,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -261,12 +261,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Triggers",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -309,12 +309,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Builds zip & pushes it",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -357,12 +357,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Pulls zip to deploy",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -405,12 +405,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Changes the live lambdas",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 795 KiB

After

Width:  |  Height:  |  Size: 799 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -56,8 +56,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -74,7 +74,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -97,8 +97,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -115,7 +115,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -138,8 +138,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -156,7 +156,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -179,8 +179,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -197,7 +197,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -220,8 +220,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -238,7 +238,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -261,12 +261,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Triggers",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -300,12 +300,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Builds zip & pushes it",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -339,12 +339,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Pulls zip to deploy",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -378,12 +378,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Changes the live lambdas",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 795 KiB

After

Width:  |  Height:  |  Size: 799 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -56,8 +56,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -74,7 +74,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -97,8 +97,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -115,7 +115,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -138,8 +138,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -156,7 +156,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -179,8 +179,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -197,7 +197,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -220,8 +220,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -238,7 +238,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -261,8 +261,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -279,7 +279,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -302,12 +302,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -350,12 +350,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -398,12 +398,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 327 KiB

After

Width:  |  Height:  |  Size: 331 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -56,8 +56,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -74,7 +74,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -97,8 +97,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -115,7 +115,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -138,8 +138,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -156,7 +156,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -179,8 +179,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -197,7 +197,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -220,8 +220,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -238,7 +238,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -261,8 +261,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#F7F8FE",
"stroke": "#0D32B2",
"fill": "B6",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -279,7 +279,7 @@
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -302,12 +302,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -349,12 +349,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -388,12 +388,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "",
"fontSize": 16,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 327 KiB

After

Width:  |  Height:  |  Size: 331 KiB

View file

@ -15,8 +15,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -33,7 +33,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -56,8 +56,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -74,7 +74,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -97,8 +97,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -115,7 +115,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -138,8 +138,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -156,7 +156,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -179,8 +179,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -197,7 +197,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -220,8 +220,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -238,7 +238,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -261,8 +261,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -279,7 +279,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -302,8 +302,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -320,7 +320,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -343,8 +343,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -361,7 +361,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -384,8 +384,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -402,7 +402,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -425,8 +425,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#E3E9FD",
"stroke": "#0D32B2",
"fill": "B4",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -443,7 +443,7 @@
"fontSize": 28,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": false,
"underline": false,
@ -466,8 +466,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -484,7 +484,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -507,8 +507,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -525,7 +525,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -548,8 +548,8 @@
"strokeDash": 0,
"strokeWidth": 2,
"borderRadius": 0,
"fill": "#EDF0FD",
"stroke": "#0D32B2",
"fill": "B5",
"stroke": "B1",
"shadow": false,
"3d": false,
"multiple": false,
@ -566,7 +566,7 @@
"fontSize": 25,
"fontFamily": "DEFAULT",
"language": "",
"color": "#0A0F25",
"color": "N1",
"italic": false,
"bold": true,
"underline": false,
@ -589,12 +589,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Triggers",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -637,12 +637,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Builds zip and pushes it",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -685,12 +685,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Pulls zip to deploy",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -733,12 +733,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Changes live lambdas",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -781,12 +781,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Launches",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -829,12 +829,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Builds zip\npushes them to S3.\n\nDeploys lambdas\nusing Terraform",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -877,12 +877,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "Triggered manually/push to master test test test test test test test",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,
@ -925,12 +925,12 @@
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
"stroke": "#0D32B2",
"stroke": "B1",
"label": "test",
"fontSize": 20,
"fontFamily": "DEFAULT",
"language": "",
"color": "#676C7E",
"color": "N2",
"italic": true,
"bold": false,
"underline": false,

Some files were not shown because too many files have changed in this diff Show more