diff --git a/d2cli/main.go b/d2cli/main.go index 40f0617e8..5c92efb5e 100644 --- a/d2cli/main.go +++ b/d2cli/main.go @@ -273,8 +273,9 @@ func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, sketc layout := plugin.Layout opts := &d2lib.CompileOptions{ - Layout: layout, - Ruler: ruler, + Layout: layout, + Ruler: ruler, + ThemeID: themeID, } if sketch { opts.FontFamily = go2.Pointer(d2fonts.HandDrawn) diff --git a/d2exporter/export.go b/d2exporter/export.go index e1b38992d..16ba3787b 100644 --- a/d2exporter/export.go +++ b/d2exporter/export.go @@ -9,6 +9,7 @@ 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/lib/color" ) @@ -20,22 +21,25 @@ func Export(ctx context.Context, g *d2graph.Graph, fontFamily *d2fonts.FontFamil if fontFamily == nil { fontFamily = go2.Pointer(d2fonts.SourceSansPro) } + if g.Theme != nil && g.Theme.SpecialRules.Mono { + fontFamily = go2.Pointer(d2fonts.SourceCodePro) + } diagram.FontFamily = fontFamily diagram.Shapes = make([]d2target.Shape, len(g.Objects)) for i := range g.Objects { - diagram.Shapes[i] = toShape(g.Objects[i]) + diagram.Shapes[i] = toShape(g.Objects[i], g.Theme) } diagram.Connections = make([]d2target.Connection, len(g.Edges)) for i := range g.Edges { - diagram.Connections[i] = toConnection(g.Edges[i]) + diagram.Connections[i] = toConnection(g.Edges[i], g.Theme) } return diagram, nil } -func applyTheme(shape *d2target.Shape, obj *d2graph.Object) { +func applyTheme(shape *d2target.Shape, obj *d2graph.Object, theme *d2themes.Theme) { shape.Stroke = obj.GetStroke(shape.StrokeDash) shape.Fill = obj.GetFill() if obj.Attributes.Shape.Value == d2target.ShapeText { @@ -46,6 +50,23 @@ func applyTheme(shape *d2target.Shape, obj *d2graph.Object) { shape.SecondaryAccentColor = color.AA2 shape.NeutralAccentColor = color.N2 } + + // Theme options that change more than color + if theme != nil { + if theme.SpecialRules.OuterContainerDoubleBorder { + if obj.Level() == 1 && len(obj.ChildrenArray) > 0 { + shape.DoubleBorder = true + } + } + if theme.SpecialRules.ContainerDots { + if len(obj.ChildrenArray) > 0 { + shape.FillPattern = "dots" + } + } + if theme.SpecialRules.Mono { + shape.FontFamily = "mono" + } + } } func applyStyles(shape *d2target.Shape, obj *d2graph.Object) { @@ -102,7 +123,7 @@ func applyStyles(shape *d2target.Shape, obj *d2graph.Object) { } } -func toShape(obj *d2graph.Object) d2target.Shape { +func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape { shape := d2target.BaseShape() shape.SetType(obj.Attributes.Shape.Value) shape.ID = obj.AbsID() @@ -127,7 +148,7 @@ func toShape(obj *d2graph.Object) d2target.Shape { } applyStyles(shape, obj) - applyTheme(shape, obj) + applyTheme(shape, obj, theme) shape.Color = text.GetColor(shape.Italic) applyStyles(shape, obj) @@ -168,7 +189,7 @@ func toShape(obj *d2graph.Object) d2target.Shape { return *shape } -func toConnection(edge *d2graph.Edge) d2target.Connection { +func toConnection(edge *d2graph.Edge, theme *d2themes.Theme) d2target.Connection { connection := d2target.BaseConnection() connection.ID = edge.AbsID() connection.ZIndex = edge.ZIndex @@ -208,7 +229,9 @@ func toConnection(edge *d2graph.Edge) d2target.Connection { connection.DstLabel = edge.DstArrowhead.Label.Value } } - + if theme != nil && theme.SpecialRules.NoCornerRadius { + connection.BorderRadius = 0 + } if edge.Attributes.Style.BorderRadius != nil { connection.BorderRadius, _ = strconv.ParseFloat(edge.Attributes.Style.BorderRadius.Value, 64) } @@ -258,6 +281,9 @@ func toConnection(edge *d2graph.Edge) d2target.Connection { if edge.Attributes.Style.Bold != nil { connection.Bold, _ = strconv.ParseBool(edge.Attributes.Style.Bold.Value) } + if theme != nil && theme.SpecialRules.Mono { + connection.FontFamily = "mono" + } if edge.Attributes.Style.Font != nil { connection.FontFamily = edge.Attributes.Style.Font.Value } diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index b8955a878..129a2f39a 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -17,6 +17,8 @@ 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/d2themes/d2themescatalog" "oss.terrastruct.com/d2/lib/color" "oss.terrastruct.com/d2/lib/geo" "oss.terrastruct.com/d2/lib/shape" @@ -43,6 +45,8 @@ type Graph struct { Layers []*Graph `json:"layers,omitempty"` Scenarios []*Graph `json:"scenarios,omitempty"` Steps []*Graph `json:"steps,omitempty"` + + Theme *d2themes.Theme `json:"theme,omitempty"` } func NewGraph() *Graph { @@ -1251,6 +1255,11 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler } } + if g.Theme != nil && g.Theme.SpecialRules.Mono { + tmp := d2fonts.SourceCodePro + fontFamily = &tmp + } + for _, obj := range g.Objects { obj.Box = &geo.Box{} @@ -1291,6 +1300,10 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler continue } + if g.Theme != nil && g.Theme.SpecialRules.CapsLock { + obj.Attributes.Label.Value = strings.ToUpper(obj.Attributes.Label.Value) + } + labelDims, err := obj.GetLabelSize(mtexts, ruler, fontFamily) if err != nil { return err @@ -1408,6 +1421,10 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler continue } + if g.Theme != nil && g.Theme.SpecialRules.CapsLock { + edge.Attributes.Label.Value = strings.ToUpper(edge.Attributes.Label.Value) + } + dims := GetTextDimensions(mtexts, ruler, edge.Text(), fontFamily) if dims == nil { return fmt.Errorf("dimensions for edge label %#v not found", edge.Text()) @@ -1650,3 +1667,15 @@ func (obj *Object) IsDescendantOf(ancestor *Object) bool { } return obj.Parent.IsDescendantOf(ancestor) } + +// ApplyTheme applies themes on the graph level +// This is different than on the render level, which only changes colors +// A theme applied on the graph level applies special rules that change the graph +func (g *Graph) ApplyTheme(themeID int64) error { + theme := d2themescatalog.Find(themeID) + if theme == (d2themes.Theme{}) { + return fmt.Errorf("theme %d not found", themeID) + } + g.Theme = &theme + return nil +} diff --git a/d2lib/d2.go b/d2lib/d2.go index e6347d303..060204ea9 100644 --- a/d2lib/d2.go +++ b/d2lib/d2.go @@ -22,6 +22,7 @@ type CompileOptions struct { MeasuredTexts []*d2target.MText Ruler *textmeasure.Ruler Layout func(context.Context, *d2graph.Graph) error + ThemeID int64 // FontFamily controls the font family used for all texts that are not the following: // - code @@ -51,6 +52,11 @@ func Compile(ctx context.Context, input string, opts *CompileOptions) (*d2target } func compile(ctx context.Context, g *d2graph.Graph, opts *CompileOptions) (*d2target.Diagram, error) { + err := g.ApplyTheme(opts.ThemeID) + if err != nil { + return nil, err + } + if len(g.Objects) > 0 { err := g.SetDimensions(opts.MeasuredTexts, opts.Ruler, opts.FontFamily) if err != nil { diff --git a/d2renderers/d2sketch/sketch_test.go b/d2renderers/d2sketch/sketch_test.go index 16b04dae9..5d578e019 100644 --- a/d2renderers/d2sketch/sketch_test.go +++ b/d2renderers/d2sketch/sketch_test.go @@ -22,6 +22,7 @@ import ( "oss.terrastruct.com/d2/d2lib" "oss.terrastruct.com/d2/d2renderers/d2fonts" "oss.terrastruct.com/d2/d2renderers/d2svg" + "oss.terrastruct.com/d2/d2themes/d2themescatalog" "oss.terrastruct.com/d2/lib/log" "oss.terrastruct.com/d2/lib/textmeasure" ) @@ -505,6 +506,54 @@ darker: { style.font-color: "#fff" style.fill: "#000" } +`, + }, + { + name: "terminal", + themeID: d2themescatalog.Terminal.ID, + script: `network: { + cell tower: { + satellites: { + shape: stored_data + style.multiple: true + } + + transmitter + + satellites -> transmitter: send + satellites -> transmitter: send + satellites -> transmitter: send + } + + online portal: { + ui: { shape: hexagon } + } + + data processor: { + storage: { + shape: cylinder + style.multiple: true + } + } + + cell tower.transmitter -> data processor.storage: phone logs +} + +user: { + shape: person + width: 130 +} + +user -> network.cell tower: make call +user -> network.online portal.ui: access { + style.stroke-dash: 3 +} + +api server -> network.online portal.ui: display +api server -> logs: persist +logs: { shape: page; style.multiple: true } + +network.data processor -> api server `, }, { @@ -1218,6 +1267,7 @@ func run(t *testing.T, tc testCase) { Ruler: ruler, Layout: layout, FontFamily: go2.Pointer(d2fonts.HandDrawn), + ThemeID: tc.themeID, }) if !tassert.Nil(t, err) { return diff --git a/d2renderers/d2sketch/testdata/terminal/sketch.exp.svg b/d2renderers/d2sketch/testdata/terminal/sketch.exp.svg new file mode 100644 index 000000000..e72fdceff --- /dev/null +++ b/d2renderers/d2sketch/testdata/terminal/sketch.exp.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +NETWORKUSERAPI SERVERLOGSCELL TOWERONLINE PORTALDATA PROCESSORSATELLITESTRANSMITTERUISTORAGE SEND SEND SEND PHONE LOGS MAKE CALL ACCESS DISPLAY PERSIST + + + + + + + + + + \ No newline at end of file diff --git a/d2renderers/d2svg/appendix/appendix_test.go b/d2renderers/d2svg/appendix/appendix_test.go index c1f3fdc11..26126327e 100644 --- a/d2renderers/d2svg/appendix/appendix_test.go +++ b/d2renderers/d2svg/appendix/appendix_test.go @@ -136,8 +136,9 @@ func run(t *testing.T, tc testCase) { } diagram, _, err := d2lib.Compile(ctx, tc.script, &d2lib.CompileOptions{ - Ruler: ruler, - Layout: d2dagrelayout.DefaultLayout, + Ruler: ruler, + Layout: d2dagrelayout.DefaultLayout, + ThemeID: tc.themeID, }) if !tassert.Nil(t, err) { return diff --git a/d2renderers/d2svg/dark_theme/dark_theme_test.go b/d2renderers/d2svg/dark_theme/dark_theme_test.go index 3e3c64974..caf81ce00 100644 --- a/d2renderers/d2svg/dark_theme/dark_theme_test.go +++ b/d2renderers/d2svg/dark_theme/dark_theme_test.go @@ -430,6 +430,7 @@ func run(t *testing.T, tc testCase) { Ruler: ruler, Layout: d2dagrelayout.DefaultLayout, FontFamily: go2.Pointer(d2fonts.HandDrawn), + ThemeID: 200, }) if !tassert.Nil(t, err) { return diff --git a/d2themes/d2themes.go b/d2themes/d2themes.go index f7fd5e327..7b6e1c267 100644 --- a/d2themes/d2themes.go +++ b/d2themes/d2themes.go @@ -8,6 +8,16 @@ type Theme struct { ID int64 `json:"id"` Name string `json:"name"` Colors ColorPalette `json:"colors"` + + SpecialRules SpecialRules `json:"specialRules,omitempty"` +} + +type SpecialRules struct { + Mono bool `json:"mono"` + NoCornerRadius bool `json:"noCornerRadius"` + OuterContainerDoubleBorder bool `json:"outerContainerDoubleBorder"` + ContainerDots bool `json:"containerDots"` + CapsLock bool `json:"capsLock"` } func (t *Theme) IsDark() bool { diff --git a/d2themes/d2themescatalog/catalog.go b/d2themes/d2themescatalog/catalog.go index 117465547..7a8b5e2aa 100644 --- a/d2themes/d2themescatalog/catalog.go +++ b/d2themes/d2themescatalog/catalog.go @@ -22,6 +22,7 @@ var LightCatalog = []d2themes.Theme{ EarthTones, EvergladeGreen, ButteredToast, + Terminal, } var DarkCatalog = []d2themes.Theme{ diff --git a/d2themes/d2themescatalog/terminal.go b/d2themes/d2themescatalog/terminal.go new file mode 100644 index 000000000..79a07e8fc --- /dev/null +++ b/d2themes/d2themescatalog/terminal.go @@ -0,0 +1,42 @@ +package d2themescatalog + +import "oss.terrastruct.com/d2/d2themes" + +var Terminal = d2themes.Theme{ + ID: 300, + Name: "Terminal", + Colors: d2themes.ColorPalette{ + Neutrals: TerminalNeutral, + + B1: "#000410", + B2: "#0000E4", + B3: "#5AA4DC", + B4: "#E7E9EE", + B5: "#F5F6F9", + B6: "#FFFFFF", + + AA2: "#008566", + AA4: "#45BBA5", + AA5: "#7ACCBD", + + AB4: "#F1C759", + AB5: "#F9E088", + }, + SpecialRules: d2themes.SpecialRules{ + Mono: true, + NoCornerRadius: true, + OuterContainerDoubleBorder: true, + ContainerDots: true, + CapsLock: true, + }, +} + +var TerminalNeutral = d2themes.Neutral{ + N1: "#000410", + N2: "#0000B8", + N3: "#9499AB", + N4: "#CFD2DD", + N5: "#C3DEF3", + N6: "#EEF1F8", + N7: "#FFFFFF", +} diff --git a/docs/examples/lib/3-lowlevel/lowlevel.go b/docs/examples/lib/3-lowlevel/lowlevel.go index 6f8420cbb..55bcea233 100644 --- a/docs/examples/lib/3-lowlevel/lowlevel.go +++ b/docs/examples/lib/3-lowlevel/lowlevel.go @@ -17,6 +17,7 @@ import ( // Remember to add if err != nil checks in production. func main() { graph, _ := d2compiler.Compile("", strings.NewReader("x -> y"), nil) + graph.ApplyTheme(d2themescatalog.NeutralDefault.ID) ruler, _ := textmeasure.NewRuler() _ = graph.SetDimensions(nil, ruler, nil) _ = d2dagrelayout.Layout(context.Background(), graph, nil) diff --git a/e2etests-cli/testdata/TestCLI_E2E/internal_linked_pdf.exp.pdf b/e2etests-cli/testdata/TestCLI_E2E/internal_linked_pdf.exp.pdf index cd314f85f..d282d6326 100644 Binary files a/e2etests-cli/testdata/TestCLI_E2E/internal_linked_pdf.exp.pdf and b/e2etests-cli/testdata/TestCLI_E2E/internal_linked_pdf.exp.pdf differ diff --git a/e2etests/e2e_test.go b/e2etests/e2e_test.go index c3339063c..7b71d909b 100644 --- a/e2etests/e2e_test.go +++ b/e2etests/e2e_test.go @@ -42,6 +42,7 @@ func TestE2E(t *testing.T) { t.Run("measured", testMeasured) t.Run("unicode", testUnicode) t.Run("root", testRoot) + t.Run("themes", testThemes) } func testSanity(t *testing.T) { @@ -86,6 +87,7 @@ type testCase struct { dagreFeatureError string elkFeatureError string expErr string + themeID int64 } func runa(t *testing.T, tcs []testCase) { @@ -163,6 +165,7 @@ func run(t *testing.T, tc testCase) { Ruler: ruler, MeasuredTexts: tc.mtexts, Layout: layout, + ThemeID: tc.themeID, }) if tc.expErr != "" { @@ -204,7 +207,7 @@ func run(t *testing.T, tc testCase) { svgBytes, err := d2svg.Render(diagram, &d2svg.RenderOpts{ Pad: 0, - ThemeID: 0, + ThemeID: tc.themeID, }) assert.Success(t, err) err = os.MkdirAll(dataPath, 0755) diff --git a/e2etests/testdata/themes/terminal/dagre/board.exp.json b/e2etests/testdata/themes/terminal/dagre/board.exp.json new file mode 100644 index 000000000..aaff0b214 --- /dev/null +++ b/e2etests/testdata/themes/terminal/dagre/board.exp.json @@ -0,0 +1,1104 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceCodePro", + "shapes": [ + { + "id": "network", + "type": "rectangle", + "pos": { + "x": 0, + "y": 275 + }, + "width": 410, + "height": 1225, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B4", + "fillPattern": "dots", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": true, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "NETWORK", + "fontSize": 28, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 116, + "labelHeight": 36, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "network.cell tower", + "type": "rectangle", + "pos": { + "x": 96, + "y": 340 + }, + "width": 294, + "height": 317, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "fillPattern": "dots", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "CELL TOWER", + "fontSize": 24, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 143, + "labelHeight": 31, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "network.cell tower.satellites", + "type": "stored_data", + "pos": { + "x": 163, + "y": 372 + }, + "width": 161, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "AA5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": true, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "SATELLITES", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 96, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "network.cell tower.transmitter", + "type": "rectangle", + "pos": { + "x": 168, + "y": 559 + }, + "width": 151, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "TRANSMITTER", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 106, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "network.online portal", + "type": "rectangle", + "pos": { + "x": 20, + "y": 1319 + }, + "width": 157, + "height": 151, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "fillPattern": "dots", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ONLINE PORTAL", + "fontSize": 24, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 185, + "labelHeight": 31, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "network.online portal.ui", + "type": "hexagon", + "pos": { + "x": 71, + "y": 1360 + }, + "width": 65, + "height": 69, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "N5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "UI", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 18, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "network.data processor", + "type": "rectangle", + "pos": { + "x": 147, + "y": 814 + }, + "width": 192, + "height": 182, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "fillPattern": "dots", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "DATA PROCESSOR", + "fontSize": 24, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 200, + "labelHeight": 31, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "network.data processor.storage", + "type": "cylinder", + "pos": { + "x": 187, + "y": 846 + }, + "width": 112, + "height": 118, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "AA5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": true, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "STORAGE", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 67, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "user", + "type": "person", + "pos": { + "x": 82, + "y": 0 + }, + "width": 130, + "height": 87, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B3", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "USER", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 38, + "labelHeight": 21, + "labelPosition": "OUTSIDE_BOTTOM_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "api server", + "type": "rectangle", + "pos": { + "x": 450, + "y": 1076 + }, + "width": 142, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "API SERVER", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 97, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "logs", + "type": "page", + "pos": { + "x": 480, + "y": 1313 + }, + "width": 82, + "height": 87, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "AB4", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": true, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "LOGS", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 37, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "network.cell tower.(satellites -> transmitter)[0]", + "src": "network.cell tower.satellites", + "srcArrow": "none", + "srcLabel": "", + "dst": "network.cell tower.transmitter", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "SEND", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 38, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 218, + "y": 439 + }, + { + "x": 182.4, + "y": 487 + }, + { + "x": 182.5, + "y": 511.2 + }, + { + "x": 218.5, + "y": 560 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "network.cell tower.(satellites -> transmitter)[1]", + "src": "network.cell tower.satellites", + "srcArrow": "none", + "srcLabel": "", + "dst": "network.cell tower.transmitter", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "SEND", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 38, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 243, + "y": 439 + }, + { + "x": 243.2, + "y": 487 + }, + { + "x": 243.25, + "y": 511.2 + }, + { + "x": 243.25, + "y": 560 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "network.cell tower.(satellites -> transmitter)[2]", + "src": "network.cell tower.satellites", + "srcArrow": "none", + "srcLabel": "", + "dst": "network.cell tower.transmitter", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "SEND", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 38, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 268, + "y": 439 + }, + { + "x": 304, + "y": 487 + }, + { + "x": 304, + "y": 511.2 + }, + { + "x": 268, + "y": 560 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "network.(cell tower.transmitter -> data processor.storage)[0]", + "src": "network.cell tower.transmitter", + "srcArrow": "none", + "srcLabel": "", + "dst": "network.data processor.storage", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "PHONE LOGS", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 96, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 243.25, + "y": 625.5 + }, + { + "x": 243.25, + "y": 651.1 + }, + { + "x": 243.25, + "y": 669.6 + }, + { + "x": 243.25, + "y": 687.75 + }, + { + "x": 243.25, + "y": 705.9 + }, + { + "x": 243.2, + "y": 792.2 + }, + { + "x": 243, + "y": 847 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(user -> network.cell tower)[0]", + "src": "user", + "srcArrow": "none", + "srcLabel": "", + "dst": "network.cell tower", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "MAKE CALL", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 86, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 172, + "y": 87 + }, + { + "x": 229, + "y": 156.2 + }, + { + "x": 243.25, + "y": 248.2 + }, + { + "x": 243.25, + "y": 305 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(user -> network.online portal.ui)[0]", + "src": "user", + "srcArrow": "none", + "srcLabel": "", + "dst": "network.online portal.ui", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 3, + "strokeWidth": 2, + "stroke": "B2", + "label": "ACCESS", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 58, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 128, + "y": 87 + }, + { + "x": 86.6, + "y": 156.2 + }, + { + "x": 76.25, + "y": 185.6 + }, + { + "x": 76.25, + "y": 203.75 + }, + { + "x": 76.25, + "y": 221.9 + }, + { + "x": 76.25, + "y": 244 + }, + { + "x": 76.25, + "y": 259 + }, + { + "x": 76.25, + "y": 274 + }, + { + "x": 76.25, + "y": 300.6 + }, + { + "x": 76.25, + "y": 325.5 + }, + { + "x": 76.25, + "y": 350.4 + }, + { + "x": 76.25, + "y": 385.7 + }, + { + "x": 76.25, + "y": 413.75 + }, + { + "x": 76.25, + "y": 441.8 + }, + { + "x": 76.25, + "y": 479.2 + }, + { + "x": 76.25, + "y": 507.25 + }, + { + "x": 76.25, + "y": 535.3 + }, + { + "x": 76.25, + "y": 570.6 + }, + { + "x": 76.25, + "y": 595.5 + }, + { + "x": 76.25, + "y": 620.4 + }, + { + "x": 76.25, + "y": 649.1 + }, + { + "x": 76.25, + "y": 667.25 + }, + { + "x": 76.25, + "y": 685.4 + }, + { + "x": 76.25, + "y": 709.6 + }, + { + "x": 76.25, + "y": 727.75 + }, + { + "x": 76.25, + "y": 745.9 + }, + { + "x": 76.25, + "y": 779.8 + }, + { + "x": 76.25, + "y": 812.5 + }, + { + "x": 76.25, + "y": 845.2 + }, + { + "x": 76.25, + "y": 888.8 + }, + { + "x": 76.25, + "y": 921.5 + }, + { + "x": 76.25, + "y": 954.2 + }, + { + "x": 76.25, + "y": 986 + }, + { + "x": 76.25, + "y": 1001 + }, + { + "x": 76.25, + "y": 1016 + }, + { + "x": 76.25, + "y": 1042.6 + }, + { + "x": 76.25, + "y": 1067.5 + }, + { + "x": 76.25, + "y": 1092.4 + }, + { + "x": 76.25, + "y": 1127.7 + }, + { + "x": 76.25, + "y": 1155.75 + }, + { + "x": 76.25, + "y": 1183.8 + }, + { + "x": 79.6, + "y": 1282.6 + }, + { + "x": 93, + "y": 1361 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(api server -> network.online portal.ui)[0]", + "src": "api server", + "srcArrow": "none", + "srcLabel": "", + "dst": "network.online portal.ui", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "DISPLAY", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 69, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 450.25, + "y": 1126 + }, + { + "x": 194.64999999999998, + "y": 1187.2 + }, + { + "x": 127.4, + "y": 1282.6 + }, + { + "x": 114, + "y": 1361 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(api server -> logs)[0]", + "src": "api server", + "srcArrow": "none", + "srcLabel": "", + "dst": "logs", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "PERSIST", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 68, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 521.25, + "y": 1142 + }, + { + "x": 521.25, + "y": 1190.4 + }, + { + "x": 521.2, + "y": 1273 + }, + { + "x": 521, + "y": 1313 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(network.data processor -> api server)[0]", + "src": "network.data processor", + "srcArrow": "none", + "srcLabel": "", + "dst": "api server", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 243.25, + "y": 996.5 + }, + { + "x": 243.25, + "y": 1020.1 + }, + { + "x": 284.65, + "y": 1038.4 + }, + { + "x": 450.25, + "y": 1088 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/themes/terminal/dagre/sketch.exp.svg b/e2etests/testdata/themes/terminal/dagre/sketch.exp.svg new file mode 100644 index 000000000..f85057442 --- /dev/null +++ b/e2etests/testdata/themes/terminal/dagre/sketch.exp.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +NETWORKUSERAPI SERVERLOGSCELL TOWERONLINE PORTALDATA PROCESSORSATELLITESTRANSMITTERUISTORAGE SENDSENDSENDPHONE LOGSMAKE CALL ACCESSDISPLAYPERSIST + + + + + + + + + + \ No newline at end of file diff --git a/e2etests/testdata/themes/terminal/elk/board.exp.json b/e2etests/testdata/themes/terminal/elk/board.exp.json new file mode 100644 index 000000000..b673875c3 --- /dev/null +++ b/e2etests/testdata/themes/terminal/elk/board.exp.json @@ -0,0 +1,895 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceCodePro", + "shapes": [ + { + "id": "network", + "type": "rectangle", + "pos": { + "x": 12, + "y": 311 + }, + "width": 611, + "height": 902, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B4", + "fillPattern": "dots", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": true, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "NETWORK", + "fontSize": 28, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 116, + "labelHeight": 36, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "network.cell tower", + "type": "rectangle", + "pos": { + "x": 62, + "y": 361 + }, + "width": 261, + "height": 413, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "fillPattern": "dots", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "CELL TOWER", + "fontSize": 24, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 143, + "labelHeight": 31, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "network.cell tower.satellites", + "type": "stored_data", + "pos": { + "x": 112, + "y": 411 + }, + "width": 161, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "AA5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": true, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "SATELLITES", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 96, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "network.cell tower.transmitter", + "type": "rectangle", + "pos": { + "x": 117, + "y": 658 + }, + "width": 151, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "TRANSMITTER", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 106, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "network.online portal", + "type": "rectangle", + "pos": { + "x": 343, + "y": 366 + }, + "width": 230, + "height": 169, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "fillPattern": "dots", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "ONLINE PORTAL", + "fontSize": 24, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 185, + "labelHeight": 31, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "network.online portal.ui", + "type": "hexagon", + "pos": { + "x": 418, + "y": 416 + }, + "width": 80, + "height": 69, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "N5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "UI", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 18, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "network.data processor", + "type": "rectangle", + "pos": { + "x": 70, + "y": 945 + }, + "width": 245, + "height": 218, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "fillPattern": "dots", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "DATA PROCESSOR", + "fontSize": 24, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 200, + "labelHeight": 31, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "network.data processor.storage", + "type": "cylinder", + "pos": { + "x": 136, + "y": 995 + }, + "width": 112, + "height": 118, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "AA5", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": true, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "STORAGE", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 67, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "user", + "type": "person", + "pos": { + "x": 314, + "y": 12 + }, + "width": 130, + "height": 87, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B3", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "USER", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 38, + "labelHeight": 21, + "labelPosition": "OUTSIDE_BOTTOM_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "api server", + "type": "rectangle", + "pos": { + "x": 592, + "y": 59 + }, + "width": 142, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "API SERVER", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 97, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "logs", + "type": "page", + "pos": { + "x": 703, + "y": 311 + }, + "width": 82, + "height": 87, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "AB4", + "stroke": "B1", + "shadow": false, + "3d": false, + "multiple": true, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "LOGS", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 37, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "network.cell tower.(satellites -> transmitter)[0]", + "src": "network.cell tower.satellites", + "srcArrow": "none", + "srcLabel": "", + "dst": "network.cell tower.transmitter", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "SEND", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 38, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 143, + "y": 477 + }, + { + "x": 143.5, + "y": 658 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "network.cell tower.(satellites -> transmitter)[1]", + "src": "network.cell tower.satellites", + "srcArrow": "none", + "srcLabel": "", + "dst": "network.cell tower.transmitter", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "SEND", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 38, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 192, + "y": 477 + }, + { + "x": 192.5, + "y": 658 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "network.cell tower.(satellites -> transmitter)[2]", + "src": "network.cell tower.satellites", + "srcArrow": "none", + "srcLabel": "", + "dst": "network.cell tower.transmitter", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "SEND", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 38, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 241, + "y": 477 + }, + { + "x": 241.5, + "y": 658 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "network.(cell tower.transmitter -> data processor.storage)[0]", + "src": "network.cell tower.transmitter", + "srcArrow": "none", + "srcLabel": "", + "dst": "network.data processor.storage", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "PHONE LOGS", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 96, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 192.5, + "y": 724 + }, + { + "x": 193, + "y": 995 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(user -> network.cell tower)[0]", + "src": "user", + "srcArrow": "none", + "srcLabel": "", + "dst": "network.cell tower", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "MAKE CALL", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 86, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 358, + "y": 99 + }, + { + "x": 357.58333333333337, + "y": 165 + }, + { + "x": 236.83333333333334, + "y": 165 + }, + { + "x": 236.83333333333334, + "y": 361 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(user -> network.online portal.ui)[0]", + "src": "user", + "srcArrow": "none", + "srcLabel": "", + "dst": "network.online portal.ui", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 3, + "strokeWidth": 2, + "stroke": "B2", + "label": "ACCESS", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 58, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 401, + "y": 99 + }, + { + "x": 400.9166666666667, + "y": 165 + }, + { + "x": 444.6666666666667, + "y": 165 + }, + { + "x": 445, + "y": 416 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(api server -> network.online portal.ui)[0]", + "src": "api server", + "srcArrow": "none", + "srcLabel": "", + "dst": "network.online portal.ui", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "DISPLAY", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 69, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 627.5, + "y": 125 + }, + { + "x": 627.5, + "y": 266 + }, + { + "x": 471.33333333333337, + "y": 266 + }, + { + "x": 471, + "y": 416 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(api server -> logs)[0]", + "src": "api server", + "srcArrow": "none", + "srcLabel": "", + "dst": "logs", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "PERSIST", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 68, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 698.5, + "y": 125 + }, + { + "x": 698.5, + "y": 165 + }, + { + "x": 744, + "y": 165 + }, + { + "x": 744, + "y": 311 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(network.data processor -> api server)[0]", + "src": "network.data processor", + "srcArrow": "none", + "srcLabel": "", + "dst": "api server", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "", + "fontSize": 16, + "fontFamily": "mono", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 136.5, + "y": 1163 + }, + { + "x": 136.5, + "y": 1258 + }, + { + "x": 663, + "y": 1258 + }, + { + "x": 663, + "y": 125 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ], + "root": { + "id": "", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 0, + "height": 0, + "opacity": 0, + "strokeDash": 0, + "strokeWidth": 0, + "borderRadius": 0, + "fill": "N7", + "stroke": "", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "zIndex": 0, + "level": 0 + } +} diff --git a/e2etests/testdata/themes/terminal/elk/sketch.exp.svg b/e2etests/testdata/themes/terminal/elk/sketch.exp.svg new file mode 100644 index 000000000..72a1e2fbf --- /dev/null +++ b/e2etests/testdata/themes/terminal/elk/sketch.exp.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +NETWORKUSERAPI SERVERLOGSCELL TOWERONLINE PORTALDATA PROCESSORSATELLITESTRANSMITTERUISTORAGE SENDSENDSENDPHONE LOGSMAKE CALL ACCESSDISPLAYPERSIST + + + + + + + + + + \ No newline at end of file diff --git a/e2etests/themes_test.go b/e2etests/themes_test.go new file mode 100644 index 000000000..47c384956 --- /dev/null +++ b/e2etests/themes_test.go @@ -0,0 +1,64 @@ +package e2etests + +import ( + _ "embed" + "testing" + + "oss.terrastruct.com/d2/d2themes/d2themescatalog" +) + +func testThemes(t *testing.T) { + tcs := []testCase{ + { + name: "terminal", + themeID: d2themescatalog.Terminal.ID, + script: ` +network: { + cell tower: { + satellites: { + shape: stored_data + style.multiple: true + } + + transmitter + + satellites -> transmitter: send + satellites -> transmitter: send + satellites -> transmitter: send + } + + online portal: { + ui: { shape: hexagon } + } + + data processor: { + storage: { + shape: cylinder + style.multiple: true + } + } + + cell tower.transmitter -> data processor.storage: phone logs +} + +user: { + shape: person + width: 130 +} + +user -> network.cell tower: make call +user -> network.online portal.ui: access { + style.stroke-dash: 3 +} + +api server -> network.online portal.ui: display +api server -> logs: persist +logs: { shape: page; style.multiple: true } + +network.data processor -> api server +`, + }, + } + + runa(t, tcs) +}