diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index a61c9436f..22610801f 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -1,5 +1,6 @@ #### Features ๐Ÿš€ +- Themes can be customized via `d2-config` vars. [#1777](https://github.com/terrastruct/d2/pull/1777) - Icons can be added for special objects (sql_table, class, code, markdown, latex). [#1774](https://github.com/terrastruct/d2/pull/1774) #### Improvements ๐Ÿงน diff --git a/d2cli/main.go b/d2cli/main.go index 12128e956..0f820ff9c 100644 --- a/d2cli/main.go +++ b/d2cli/main.go @@ -845,13 +845,15 @@ func _render(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts scale = go2.Pointer(1.) } svg, err := d2svg.Render(diagram, &d2svg.RenderOpts{ - Pad: opts.Pad, - Sketch: opts.Sketch, - Center: opts.Center, - ThemeID: opts.ThemeID, - DarkThemeID: opts.DarkThemeID, - MasterID: opts.MasterID, - Scale: scale, + Pad: opts.Pad, + Sketch: opts.Sketch, + Center: opts.Center, + ThemeID: opts.ThemeID, + DarkThemeID: opts.DarkThemeID, + MasterID: opts.MasterID, + ThemeOverrides: opts.ThemeOverrides, + DarkThemeOverrides: opts.DarkThemeOverrides, + Scale: scale, }) if err != nil { return nil, err diff --git a/d2compiler/compile.go b/d2compiler/compile.go index 4a51d2457..3d4d1fcb1 100644 --- a/d2compiler/compile.go +++ b/d2compiler/compile.go @@ -17,6 +17,7 @@ import ( "oss.terrastruct.com/d2/d2ir" "oss.terrastruct.com/d2/d2parser" "oss.terrastruct.com/d2/d2target" + "oss.terrastruct.com/d2/lib/color" "oss.terrastruct.com/d2/lib/textmeasure" ) @@ -54,7 +55,11 @@ func Compile(p string, r io.Reader, opts *CompileOptions) (*d2graph.Graph, *d2ta g.FS = opts.FS g.SortObjectsByAST() g.SortEdgesByAST() - return g, compileConfig(ir), nil + config, err := compileConfig(ir) + if err != nil { + return nil, nil, err + } + return g, config, nil } func compileIR(ast *d2ast.Map, m *d2ir.Map) (*d2graph.Graph, error) { @@ -1336,10 +1341,10 @@ func parentSeqDiagram(n d2ir.Node) *d2ir.Map { } } -func compileConfig(ir *d2ir.Map) *d2target.Config { +func compileConfig(ir *d2ir.Map) (*d2target.Config, error) { f := ir.GetField("vars", "d2-config") if f == nil || f.Map() == nil { - return nil + return nil, nil } configMap := f.Map() @@ -1375,5 +1380,87 @@ func compileConfig(ir *d2ir.Map) *d2target.Config { config.LayoutEngine = go2.Pointer(f.Primary().Value.ScalarString()) } - return config + f = configMap.GetField("theme-overrides") + if f != nil { + overrides, err := compileThemeOverrides(f.Map()) + if err != nil { + return nil, err + } + config.ThemeOverrides = overrides + } + f = configMap.GetField("dark-theme-overrides") + if f != nil { + overrides, err := compileThemeOverrides(f.Map()) + if err != nil { + return nil, err + } + config.DarkThemeOverrides = overrides + } + + return config, nil +} + +func compileThemeOverrides(m *d2ir.Map) (*d2target.ThemeOverrides, error) { + if m == nil { + return nil, nil + } + themeOverrides := d2target.ThemeOverrides{} + + err := &d2parser.ParseError{} +FOR: + for _, f := range m.Fields { + switch strings.ToUpper(f.Name) { + case "N1": + themeOverrides.N1 = go2.Pointer(f.Primary().Value.ScalarString()) + case "N2": + themeOverrides.N2 = go2.Pointer(f.Primary().Value.ScalarString()) + case "N3": + themeOverrides.N3 = go2.Pointer(f.Primary().Value.ScalarString()) + case "N4": + themeOverrides.N4 = go2.Pointer(f.Primary().Value.ScalarString()) + case "N5": + themeOverrides.N5 = go2.Pointer(f.Primary().Value.ScalarString()) + case "N6": + themeOverrides.N6 = go2.Pointer(f.Primary().Value.ScalarString()) + case "N7": + themeOverrides.N7 = go2.Pointer(f.Primary().Value.ScalarString()) + case "B1": + themeOverrides.B1 = go2.Pointer(f.Primary().Value.ScalarString()) + case "B2": + themeOverrides.B2 = go2.Pointer(f.Primary().Value.ScalarString()) + case "B3": + themeOverrides.B3 = go2.Pointer(f.Primary().Value.ScalarString()) + case "B4": + themeOverrides.B4 = go2.Pointer(f.Primary().Value.ScalarString()) + case "B5": + themeOverrides.B5 = go2.Pointer(f.Primary().Value.ScalarString()) + case "B6": + themeOverrides.B6 = go2.Pointer(f.Primary().Value.ScalarString()) + case "AA2": + themeOverrides.AA2 = go2.Pointer(f.Primary().Value.ScalarString()) + case "AA4": + themeOverrides.AA4 = go2.Pointer(f.Primary().Value.ScalarString()) + case "AA5": + themeOverrides.AA5 = go2.Pointer(f.Primary().Value.ScalarString()) + case "AB4": + themeOverrides.AB4 = go2.Pointer(f.Primary().Value.ScalarString()) + case "AB5": + themeOverrides.AB5 = go2.Pointer(f.Primary().Value.ScalarString()) + default: + err.Errors = append(err.Errors, d2parser.Errorf(f.LastPrimaryKey(), fmt.Sprintf(`"%s" is not a valid theme code`, f.Name)).(d2ast.Error)) + continue FOR + } + if !go2.Contains(color.NamedColors, strings.ToLower(f.Primary().Value.ScalarString())) && !color.ColorHexRegex.MatchString(f.Primary().Value.ScalarString()) { + err.Errors = append(err.Errors, d2parser.Errorf(f.LastPrimaryKey(), fmt.Sprintf(`expected "%s" to be a valid named color ("orange") or a hex code ("#f0ff3a")`, f.Name)).(d2ast.Error)) + } + } + + if !err.Empty() { + return nil, err + } + + if themeOverrides != (d2target.ThemeOverrides{}) { + return &themeOverrides, nil + } + return nil, nil } diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index 4ba50f013..c74398934 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -2812,6 +2812,21 @@ g: |md d2/testdata/d2compiler/TestCompile/text_no_label.d2:15:1: block string cannot be empty d2/testdata/d2compiler/TestCompile/text_no_label.d2:4:1: shape text must have a non-empty label d2/testdata/d2compiler/TestCompile/text_no_label.d2:7:1: shape text must have a non-empty label`, + }, + { + name: "var-not-color", + text: `vars: { + d2-config: { + theme-overrides: { + B1: potato + potato: B1 + } + } +} +a +`, + expErr: `d2/testdata/d2compiler/TestCompile/var-not-color.d2:4:7: expected "B1" to be a valid named color ("orange") or a hex code ("#f0ff3a") +d2/testdata/d2compiler/TestCompile/var-not-color.d2:5:4: "potato" is not a valid theme code`, }, { name: "no_arrowheads_in_shape", diff --git a/d2graph/color_helper.go b/d2graph/color_helper.go deleted file mode 100644 index 4615847a4..000000000 --- a/d2graph/color_helper.go +++ /dev/null @@ -1,159 +0,0 @@ -package d2graph - -import "regexp" - -// namedColors is a list of valid CSS colors -var namedColors = []string{ - "currentcolor", - "transparent", - "aliceblue", - "antiquewhite", - "aqua", - "aquamarine", - "azure", - "beige", - "bisque", - "black", - "blanchedalmond", - "blue", - "blueviolet", - "brown", - "burlywood", - "cadetblue", - "chartreuse", - "chocolate", - "coral", - "cornflowerblue", - "cornsilk", - "crimson", - "cyan", - "darkblue", - "darkcyan", - "darkgoldenrod", - "darkgray", - "darkgrey", - "darkgreen", - "darkkhaki", - "darkmagenta", - "darkolivegreen", - "darkorange", - "darkorchid", - "darkred", - "darksalmon", - "darkseagreen", - "darkslateblue", - "darkslategray", - "darkslategrey", - "darkturquoise", - "darkviolet", - "deeppink", - "deepskyblue", - "dimgray", - "dimgrey", - "dodgerblue", - "firebrick", - "floralwhite", - "forestgreen", - "fuchsia", - "gainsboro", - "ghostwhite", - "gold", - "goldenrod", - "gray", - "grey", - "green", - "greenyellow", - "honeydew", - "hotpink", - "indianred", - "indigo", - "ivory", - "khaki", - "lavender", - "lavenderblush", - "lawngreen", - "lemonchiffon", - "lightblue", - "lightcoral", - "lightcyan", - "lightgoldenrodyellow", - "lightgray", - "lightgrey", - "lightgreen", - "lightpink", - "lightsalmon", - "lightseagreen", - "lightskyblue", - "lightslategray", - "lightslategrey", - "lightsteelblue", - "lightyellow", - "lime", - "limegreen", - "linen", - "magenta", - "maroon", - "mediumaquamarine", - "mediumblue", - "mediumorchid", - "mediumpurple", - "mediumseagreen", - "mediumslateblue", - "mediumspringgreen", - "mediumturquoise", - "mediumvioletred", - "midnightblue", - "mintcream", - "mistyrose", - "moccasin", - "navajowhite", - "navy", - "oldlace", - "olive", - "olivedrab", - "orange", - "orangered", - "orchid", - "palegoldenrod", - "palegreen", - "paleturquoise", - "palevioletred", - "papayawhip", - "peachpuff", - "peru", - "pink", - "plum", - "powderblue", - "purple", - "rebeccapurple", - "red", - "rosybrown", - "royalblue", - "saddlebrown", - "salmon", - "sandybrown", - "seagreen", - "seashell", - "sienna", - "silver", - "skyblue", - "slateblue", - "slategray", - "slategrey", - "snow", - "springgreen", - "steelblue", - "tan", - "teal", - "thistle", - "tomato", - "turquoise", - "violet", - "wheat", - "white", - "whitesmoke", - "yellow", - "yellowgreen", -} - -var colorHexRegex = regexp.MustCompile(`^#(([0-9a-fA-F]{2}){3}|([0-9a-fA-F]){3})$`) diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index 9fece76c1..b70c887bd 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -252,7 +252,7 @@ func (s *Style) Apply(key, value string) error { if s.Stroke == nil { break } - if !go2.Contains(namedColors, strings.ToLower(value)) && !colorHexRegex.MatchString(value) { + if !go2.Contains(color.NamedColors, strings.ToLower(value)) && !color.ColorHexRegex.MatchString(value) { return errors.New(`expected "stroke" to be a valid named color ("orange") or a hex code ("#f0ff3a")`) } s.Stroke.Value = value @@ -260,7 +260,7 @@ func (s *Style) Apply(key, value string) error { if s.Fill == nil { break } - if !go2.Contains(namedColors, strings.ToLower(value)) && !colorHexRegex.MatchString(value) { + if !go2.Contains(color.NamedColors, strings.ToLower(value)) && !color.ColorHexRegex.MatchString(value) { return errors.New(`expected "fill" to be a valid named color ("orange") or a hex code ("#f0ff3a")`) } s.Fill.Value = value @@ -347,7 +347,7 @@ func (s *Style) Apply(key, value string) error { if s.FontColor == nil { break } - if !go2.Contains(namedColors, strings.ToLower(value)) && !colorHexRegex.MatchString(value) { + if !go2.Contains(color.NamedColors, strings.ToLower(value)) && !color.ColorHexRegex.MatchString(value) { return errors.New(`expected "font-color" to be a valid named color ("orange") or a hex code ("#f0ff3a")`) } s.FontColor.Value = value diff --git a/d2ir/compile.go b/d2ir/compile.go index 6e3f9b249..4a061db07 100644 --- a/d2ir/compile.go +++ b/d2ir/compile.go @@ -169,7 +169,7 @@ func (c *compiler) validateConfigs(configs *Field) { for _, f := range configs.Map().Fields { var val string if f.Primary() == nil { - if f.Name != "theme-colors" { + if f.Name != "theme-overrides" && f.Name != "dark-theme-overrides" { c.errorf(f.LastRef().AST(), `"%s" needs a value`, f.Name) continue } @@ -184,7 +184,7 @@ func (c *compiler) validateConfigs(configs *Field) { c.errorf(f.LastRef().AST(), `expected a boolean for "%s", got "%s"`, f.Name, val) continue } - case "theme-colors": + case "theme-overrides", "dark-theme-overrides": if f.Map() == nil { c.errorf(f.LastRef().AST(), `"%s" needs a map`, f.Name) continue diff --git a/d2lib/d2.go b/d2lib/d2.go index 50d64945a..c8cdb1167 100644 --- a/d2lib/d2.go +++ b/d2lib/d2.go @@ -188,6 +188,8 @@ func applyConfigs(config *d2target.Config, compileOpts *CompileOptions, renderOp if renderOpts.Center == nil { renderOpts.Center = config.Center } + renderOpts.ThemeOverrides = config.ThemeOverrides + renderOpts.DarkThemeOverrides = config.DarkThemeOverrides } func applyDefaults(compileOpts *CompileOptions, renderOpts *d2svg.RenderOpts) { diff --git a/d2renderers/d2animate/d2animate.go b/d2renderers/d2animate/d2animate.go index 9eed2bf10..460bfa5f3 100644 --- a/d2renderers/d2animate/d2animate.go +++ b/d2renderers/d2animate/d2animate.go @@ -76,7 +76,7 @@ func Wrap(rootDiagram *d2target.Diagram, svgs [][]byte, renderOpts d2svg.RenderO d2svg.EmbedFonts(buf, diagramHash, svgsStr, rootDiagram.FontFamily, rootDiagram.GetNestedCorpus()) - themeStylesheet, err := d2svg.ThemeCSS(diagramHash, renderOpts.ThemeID, renderOpts.DarkThemeID) + themeStylesheet, err := d2svg.ThemeCSS(diagramHash, renderOpts.ThemeID, renderOpts.DarkThemeID, renderOpts.ThemeOverrides, renderOpts.DarkThemeOverrides) if err != nil { return nil, err } diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go index 6ee011d88..68e2f1852 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -69,12 +69,14 @@ var grain string var paper string type RenderOpts struct { - Pad *int64 - Sketch *bool - Center *bool - ThemeID *int64 - DarkThemeID *int64 - Font string + Pad *int64 + Sketch *bool + Center *bool + ThemeID *int64 + DarkThemeID *int64 + ThemeOverrides *d2target.ThemeOverrides + DarkThemeOverrides *d2target.ThemeOverrides + Font string // the svg will be scaled by this factor, if unset the svg will fit to screen Scale *float64 @@ -1854,7 +1856,7 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) { upperBuf := &bytes.Buffer{} if opts.MasterID == "" { EmbedFonts(upperBuf, diagramHash, buf.String(), diagram.FontFamily, diagram.GetCorpus()) // EmbedFonts *must* run before `d2sketch.DefineFillPatterns`, but after all elements are appended to `buf` - themeStylesheet, err := ThemeCSS(diagramHash, &themeID, darkThemeID) + themeStylesheet, err := ThemeCSS(diagramHash, &themeID, darkThemeID, opts.ThemeOverrides, opts.DarkThemeOverrides) if err != nil { return nil, err } @@ -2016,17 +2018,17 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) { } // TODO include only colors that are being used to reduce size -func ThemeCSS(diagramHash string, themeID *int64, darkThemeID *int64) (stylesheet string, err error) { +func ThemeCSS(diagramHash string, themeID *int64, darkThemeID *int64, overrides, darkOverrides *d2target.ThemeOverrides) (stylesheet string, err error) { if themeID == nil { themeID = &d2themescatalog.NeutralDefault.ID } - out, err := singleThemeRulesets(diagramHash, *themeID) + out, err := singleThemeRulesets(diagramHash, *themeID, overrides) if err != nil { return "", err } if darkThemeID != nil { - darkOut, err := singleThemeRulesets(diagramHash, *darkThemeID) + darkOut, err := singleThemeRulesets(diagramHash, *darkThemeID, darkOverrides) if err != nil { return "", err } @@ -2036,9 +2038,10 @@ func ThemeCSS(diagramHash string, themeID *int64, darkThemeID *int64) (styleshee return out, nil } -func singleThemeRulesets(diagramHash string, themeID int64) (rulesets string, err error) { +func singleThemeRulesets(diagramHash string, themeID int64, overrides *d2target.ThemeOverrides) (rulesets string, err error) { out := "" theme := d2themescatalog.Find(themeID) + theme.ApplyOverrides(overrides) // Global theme colors for _, property := range []string{"fill", "stroke", "background-color", "color"} { diff --git a/d2target/d2target.go b/d2target/d2target.go index f5448c2f0..f9153faa2 100644 --- a/d2target/d2target.go +++ b/d2target/d2target.go @@ -39,18 +39,35 @@ const ( var BorderOffset = geo.NewVector(5, 5) type Config struct { - Sketch *bool `json:"sketch"` - ThemeID *int64 `json:"themeID"` - DarkThemeID *int64 `json:"darkThemeID"` - Pad *int64 `json:"pad"` - Center *bool `json:"center"` - LayoutEngine *string `json:"layoutEngine"` - ThemeOverrides *ThemeOverrides `json:"themeOverrides"` + Sketch *bool `json:"sketch"` + ThemeID *int64 `json:"themeID"` + DarkThemeID *int64 `json:"darkThemeID"` + Pad *int64 `json:"pad"` + Center *bool `json:"center"` + LayoutEngine *string `json:"layoutEngine"` + ThemeOverrides *ThemeOverrides `json:"themeOverrides,omitempty"` + DarkThemeOverrides *ThemeOverrides `json:"darkThemeOverrides,omitempty"` } type ThemeOverrides struct { - N1 *string `json:"n1"` - // TODO + N1 *string `json:"n1"` + N2 *string `json:"n2"` + N3 *string `json:"n3"` + N4 *string `json:"n4"` + N5 *string `json:"n5"` + N6 *string `json:"n6"` + N7 *string `json:"n7"` + B1 *string `json:"b1"` + B2 *string `json:"b2"` + B3 *string `json:"b3"` + B4 *string `json:"b4"` + B5 *string `json:"b5"` + B6 *string `json:"b6"` + AA2 *string `json:"aa2"` + AA4 *string `json:"aa4"` + AA5 *string `json:"aa5"` + AB4 *string `json:"ab4"` + AB5 *string `json:"ab5"` } type Diagram struct { diff --git a/d2themes/d2themes.go b/d2themes/d2themes.go index f1703a226..48313e3ff 100644 --- a/d2themes/d2themes.go +++ b/d2themes/d2themes.go @@ -2,7 +2,10 @@ // Color codes: darkest (N1) -> lightest (N7) package d2themes -import "oss.terrastruct.com/d2/lib/color" +import ( + "oss.terrastruct.com/d2/d2target" + "oss.terrastruct.com/d2/lib/color" +) type Theme struct { ID int64 `json:"id"` @@ -26,6 +29,70 @@ func (t *Theme) IsDark() bool { return t.ID >= 200 && t.ID < 300 } +func (t *Theme) ApplyOverrides(overrides *d2target.ThemeOverrides) { + if overrides == nil { + return + } + + if overrides.B1 != nil { + t.Colors.B1 = *overrides.B1 + } + if overrides.B2 != nil { + t.Colors.B2 = *overrides.B2 + } + if overrides.B3 != nil { + t.Colors.B3 = *overrides.B3 + } + if overrides.B4 != nil { + t.Colors.B4 = *overrides.B4 + } + if overrides.B5 != nil { + t.Colors.B5 = *overrides.B5 + } + if overrides.B5 != nil { + t.Colors.B5 = *overrides.B5 + } + if overrides.B6 != nil { + t.Colors.B6 = *overrides.B6 + } + if overrides.AA2 != nil { + t.Colors.AA2 = *overrides.AA2 + } + if overrides.AA4 != nil { + t.Colors.AA4 = *overrides.AA4 + } + if overrides.AA5 != nil { + t.Colors.AA5 = *overrides.AA5 + } + if overrides.AB4 != nil { + t.Colors.AB4 = *overrides.AB4 + } + if overrides.AB5 != nil { + t.Colors.AB5 = *overrides.AB5 + } + if overrides.N1 != nil { + t.Colors.Neutrals.N1 = *overrides.N1 + } + if overrides.N2 != nil { + t.Colors.Neutrals.N2 = *overrides.N2 + } + if overrides.N3 != nil { + t.Colors.Neutrals.N3 = *overrides.N3 + } + if overrides.N4 != nil { + t.Colors.Neutrals.N4 = *overrides.N4 + } + if overrides.N5 != nil { + t.Colors.Neutrals.N5 = *overrides.N5 + } + if overrides.N6 != nil { + t.Colors.Neutrals.N6 = *overrides.N6 + } + if overrides.N7 != nil { + t.Colors.Neutrals.N7 = *overrides.N7 + } +} + type Neutral struct { N1 string `json:"n1"` N2 string `json:"n2"` diff --git a/e2etests-cli/main_test.go b/e2etests-cli/main_test.go index c0e1a7ac1..8da9444b2 100644 --- a/e2etests-cli/main_test.go +++ b/e2etests-cli/main_test.go @@ -350,6 +350,133 @@ layers: { assert.Testdata(t, ".svg", svg) }, }, + { + name: "theme-override", + run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) { + writeFile(t, dir, "theme-override.d2", ` +direction: right +vars: { + d2-config: { + theme-overrides: { + B1: "#2E7D32" + B2: "#66BB6A" + B3: "#A5D6A7" + B4: "#C5E1A5" + B5: "#E6EE9C" + B6: "#FFF59D" + + AA2: "#0D47A1" + AA4: "#42A5F5" + AA5: "#90CAF9" + + AB4: "#F44336" + AB5: "#FFCDD2" + + N1: "#2E2E2E" + N2: "#2E2E2E" + N3: "#595959" + N4: "#858585" + N5: "#B1B1B1" + N6: "#DCDCDC" + N7: "#DCDCDC" + } + dark-theme-overrides: { + B1: "#2E7D32" + B2: "#66BB6A" + B3: "#A5D6A7" + B4: "#C5E1A5" + B5: "#E6EE9C" + B6: "#FFF59D" + + AA2: "#0D47A1" + AA4: "#42A5F5" + AA5: "#90CAF9" + + AB4: "#F44336" + AB5: "#FFCDD2" + + N1: "#2E2E2E" + N2: "#2E2E2E" + N3: "#595959" + N4: "#858585" + N5: "#B1B1B1" + N6: "#DCDCDC" + N7: "#DCDCDC" + } + } +} + +logs: { + shape: page + style.multiple: true +} +user: User {shape: person} +network: Network { + tower: Cell Tower { + satellites: { + shape: stored_data + style.multiple: true + } + + satellites -> transmitter + satellites -> transmitter + satellites -> transmitter + transmitter + } + processor: Data Processor { + storage: Storage { + shape: cylinder + style.multiple: true + } + } + portal: Online Portal { + UI + } + + tower.transmitter -> processor: phone logs +} +server: API Server + +user -> network.tower: Make call +network.processor -> server +network.processor -> server +network.processor -> server + +server -> logs +server -> logs +server -> logs: persist + +server -> network.portal.UI: display +user -> network.portal.UI: access { + style.stroke-dash: 3 +} + +costumes: { + shape: sql_table + id: int {constraint: primary_key} + silliness: int + monster: int + last_updated: timestamp +} + +monsters: { + shape: sql_table + id: int {constraint: primary_key} + movie: string + weight: int + last_updated: timestamp +} + +costumes.monster -> monsters.id +`) + err := runTestMain(t, ctx, dir, env, "theme-override.d2", "theme-override.svg") + assert.Success(t, err) + svg := readFile(t, dir, "theme-override.svg") + assert.Testdata(t, ".svg", svg) + // theme color is used in SVG + assert.NotEqual(t, -1, strings.Index(string(svg), "#2E2E2E")) + }, + }, { name: "multiboard/life", run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) { diff --git a/e2etests-cli/testdata/TestCLI_E2E/import_vars.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/import_vars.exp.svg index 543997887..d844683d1 100644 --- a/e2etests-cli/testdata/TestCLI_E2E/import_vars.exp.svg +++ b/e2etests-cli/testdata/TestCLI_E2E/import_vars.exp.svg @@ -1,9 +1,9 @@ -xy + .d2-2712468095 .fill-N1{fill:#CDD6F4;} + .d2-2712468095 .fill-N2{fill:#BAC2DE;} + .d2-2712468095 .fill-N3{fill:#A6ADC8;} + .d2-2712468095 .fill-N4{fill:#585B70;} + .d2-2712468095 .fill-N5{fill:#45475A;} + .d2-2712468095 .fill-N6{fill:#313244;} + .d2-2712468095 .fill-N7{fill:#1E1E2E;} + .d2-2712468095 .fill-B1{fill:#CBA6f7;} + .d2-2712468095 .fill-B2{fill:#CBA6f7;} + .d2-2712468095 .fill-B3{fill:#6C7086;} + .d2-2712468095 .fill-B4{fill:#585B70;} + .d2-2712468095 .fill-B5{fill:#45475A;} + .d2-2712468095 .fill-B6{fill:#313244;} + .d2-2712468095 .fill-AA2{fill:#f38BA8;} + .d2-2712468095 .fill-AA4{fill:#45475A;} + .d2-2712468095 .fill-AA5{fill:#313244;} + .d2-2712468095 .fill-AB4{fill:#45475A;} + .d2-2712468095 .fill-AB5{fill:#313244;} + .d2-2712468095 .stroke-N1{stroke:#CDD6F4;} + .d2-2712468095 .stroke-N2{stroke:#BAC2DE;} + .d2-2712468095 .stroke-N3{stroke:#A6ADC8;} + .d2-2712468095 .stroke-N4{stroke:#585B70;} + .d2-2712468095 .stroke-N5{stroke:#45475A;} + .d2-2712468095 .stroke-N6{stroke:#313244;} + .d2-2712468095 .stroke-N7{stroke:#1E1E2E;} + .d2-2712468095 .stroke-B1{stroke:#CBA6f7;} + .d2-2712468095 .stroke-B2{stroke:#CBA6f7;} + .d2-2712468095 .stroke-B3{stroke:#6C7086;} + .d2-2712468095 .stroke-B4{stroke:#585B70;} + .d2-2712468095 .stroke-B5{stroke:#45475A;} + .d2-2712468095 .stroke-B6{stroke:#313244;} + .d2-2712468095 .stroke-AA2{stroke:#f38BA8;} + .d2-2712468095 .stroke-AA4{stroke:#45475A;} + .d2-2712468095 .stroke-AA5{stroke:#313244;} + .d2-2712468095 .stroke-AB4{stroke:#45475A;} + .d2-2712468095 .stroke-AB5{stroke:#313244;} + .d2-2712468095 .background-color-N1{background-color:#CDD6F4;} + .d2-2712468095 .background-color-N2{background-color:#BAC2DE;} + .d2-2712468095 .background-color-N3{background-color:#A6ADC8;} + .d2-2712468095 .background-color-N4{background-color:#585B70;} + .d2-2712468095 .background-color-N5{background-color:#45475A;} + .d2-2712468095 .background-color-N6{background-color:#313244;} + .d2-2712468095 .background-color-N7{background-color:#1E1E2E;} + .d2-2712468095 .background-color-B1{background-color:#CBA6f7;} + .d2-2712468095 .background-color-B2{background-color:#CBA6f7;} + .d2-2712468095 .background-color-B3{background-color:#6C7086;} + .d2-2712468095 .background-color-B4{background-color:#585B70;} + .d2-2712468095 .background-color-B5{background-color:#45475A;} + .d2-2712468095 .background-color-B6{background-color:#313244;} + .d2-2712468095 .background-color-AA2{background-color:#f38BA8;} + .d2-2712468095 .background-color-AA4{background-color:#45475A;} + .d2-2712468095 .background-color-AA5{background-color:#313244;} + .d2-2712468095 .background-color-AB4{background-color:#45475A;} + .d2-2712468095 .background-color-AB5{background-color:#313244;} + .d2-2712468095 .color-N1{color:#CDD6F4;} + .d2-2712468095 .color-N2{color:#BAC2DE;} + .d2-2712468095 .color-N3{color:#A6ADC8;} + .d2-2712468095 .color-N4{color:#585B70;} + .d2-2712468095 .color-N5{color:#45475A;} + .d2-2712468095 .color-N6{color:#313244;} + .d2-2712468095 .color-N7{color:#1E1E2E;} + .d2-2712468095 .color-B1{color:#CBA6f7;} + .d2-2712468095 .color-B2{color:#CBA6f7;} + .d2-2712468095 .color-B3{color:#6C7086;} + .d2-2712468095 .color-B4{color:#585B70;} + .d2-2712468095 .color-B5{color:#45475A;} + .d2-2712468095 .color-B6{color:#313244;} + .d2-2712468095 .color-AA2{color:#f38BA8;} + .d2-2712468095 .color-AA4{color:#45475A;} + .d2-2712468095 .color-AA5{color:#313244;} + .d2-2712468095 .color-AB4{color:#45475A;} + .d2-2712468095 .color-AB5{color:#313244;}.appendix text.text{fill:#CDD6F4}.md{--color-fg-default:#CDD6F4;--color-fg-muted:#BAC2DE;--color-fg-subtle:#A6ADC8;--color-canvas-default:#1E1E2E;--color-canvas-subtle:#313244;--color-border-default:#CBA6f7;--color-border-muted:#CBA6f7;--color-neutral-muted:#313244;--color-accent-fg:#CBA6f7;--color-accent-emphasis:#CBA6f7;--color-attention-subtle:#BAC2DE;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-B2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-B3{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-B4{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-B5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B6{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AA2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-AA4{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AA5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AB4{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-AB5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N1{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N2{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N5{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N6{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N7{fill:url(#streaks-darker);mix-blend-mode:lighten}.light-code{display: none}.dark-code{display: block}]]>xy 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 751aa45ac..ca96dd593 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-cli/testdata/TestCLI_E2E/no-nav-pdf.exp.pdf b/e2etests-cli/testdata/TestCLI_E2E/no-nav-pdf.exp.pdf index bfc825b34..887985d78 100644 Binary files a/e2etests-cli/testdata/TestCLI_E2E/no-nav-pdf.exp.pdf and b/e2etests-cli/testdata/TestCLI_E2E/no-nav-pdf.exp.pdf differ diff --git a/e2etests-cli/testdata/TestCLI_E2E/no-nav-pptx.exp.pptx b/e2etests-cli/testdata/TestCLI_E2E/no-nav-pptx.exp.pptx index acca7f844..657a8e60f 100644 Binary files a/e2etests-cli/testdata/TestCLI_E2E/no-nav-pptx.exp.pptx and b/e2etests-cli/testdata/TestCLI_E2E/no-nav-pptx.exp.pptx differ diff --git a/e2etests-cli/testdata/TestCLI_E2E/renamed-board.exp.pdf b/e2etests-cli/testdata/TestCLI_E2E/renamed-board.exp.pdf index 6a9b2b0eb..dd0b54a1c 100644 Binary files a/e2etests-cli/testdata/TestCLI_E2E/renamed-board.exp.pdf and b/e2etests-cli/testdata/TestCLI_E2E/renamed-board.exp.pdf differ diff --git a/e2etests-cli/testdata/TestCLI_E2E/theme-override.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/theme-override.exp.svg new file mode 100644 index 000000000..481fb6b96 --- /dev/null +++ b/e2etests-cli/testdata/TestCLI_E2E/theme-override.exp.svg @@ -0,0 +1,124 @@ +logsUserNetworkAPI ServercostumesidintPKsillinessintmonsterintlast_updatedtimestampmonstersidintPKmoviestringweightintlast_updatedtimestampCell TowerData ProcessorOnline PortalsatellitestransmitterStorageUI phone logsMake callpersistdisplay access + + + + + + + + + + + + + + + + + + diff --git a/e2etests-cli/testdata/TestCLI_E2E/vars-animation.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/vars-animation.exp.svg index 773c44771..a4327293c 100644 --- a/e2etests-cli/testdata/TestCLI_E2E/vars-animation.exp.svg +++ b/e2etests-cli/testdata/TestCLI_E2E/vars-animation.exp.svg @@ -1,16 +1,16 @@ CHICKEN'S PLAN +}]]>CHICKEN'S PLAN -CHICKEN'S PLANAPPROACH ROAD +CHICKEN'S PLANAPPROACH ROAD -CHICKEN'S PLANAPPROACH ROADCROSS ROAD +CHICKEN'S PLANAPPROACH ROADCROSS ROAD -CHICKEN'S PLANAPPROACH ROADCROSS ROADMAKE YOU WONDER WHY +CHICKEN'S PLANAPPROACH ROADCROSS ROADMAKE YOU WONDER WHY diff --git a/e2etests-cli/testdata/TestCLI_E2E/vars-config.exp.svg b/e2etests-cli/testdata/TestCLI_E2E/vars-config.exp.svg index 34c4a8056..8721ac0df 100644 --- a/e2etests-cli/testdata/TestCLI_E2E/vars-config.exp.svg +++ b/e2etests-cli/testdata/TestCLI_E2E/vars-config.exp.svg @@ -1,16 +1,16 @@ - + .d2-2303466848 .fill-N1{fill:#0A0F25;} + .d2-2303466848 .fill-N2{fill:#676C7E;} + .d2-2303466848 .fill-N3{fill:#9499AB;} + .d2-2303466848 .fill-N4{fill:#CFD2DD;} + .d2-2303466848 .fill-N5{fill:#DEE1EB;} + .d2-2303466848 .fill-N6{fill:#EEF1F8;} + .d2-2303466848 .fill-N7{fill:#FFFFFF;} + .d2-2303466848 .fill-B1{fill:#0A0F25;} + .d2-2303466848 .fill-B2{fill:#676C7E;} + .d2-2303466848 .fill-B3{fill:#9499AB;} + .d2-2303466848 .fill-B4{fill:#CFD2DD;} + .d2-2303466848 .fill-B5{fill:#DEE1EB;} + .d2-2303466848 .fill-B6{fill:#EEF1F8;} + .d2-2303466848 .fill-AA2{fill:#676C7E;} + .d2-2303466848 .fill-AA4{fill:#CFD2DD;} + .d2-2303466848 .fill-AA5{fill:#DEE1EB;} + .d2-2303466848 .fill-AB4{fill:#CFD2DD;} + .d2-2303466848 .fill-AB5{fill:#DEE1EB;} + .d2-2303466848 .stroke-N1{stroke:#0A0F25;} + .d2-2303466848 .stroke-N2{stroke:#676C7E;} + .d2-2303466848 .stroke-N3{stroke:#9499AB;} + .d2-2303466848 .stroke-N4{stroke:#CFD2DD;} + .d2-2303466848 .stroke-N5{stroke:#DEE1EB;} + .d2-2303466848 .stroke-N6{stroke:#EEF1F8;} + .d2-2303466848 .stroke-N7{stroke:#FFFFFF;} + .d2-2303466848 .stroke-B1{stroke:#0A0F25;} + .d2-2303466848 .stroke-B2{stroke:#676C7E;} + .d2-2303466848 .stroke-B3{stroke:#9499AB;} + .d2-2303466848 .stroke-B4{stroke:#CFD2DD;} + .d2-2303466848 .stroke-B5{stroke:#DEE1EB;} + .d2-2303466848 .stroke-B6{stroke:#EEF1F8;} + .d2-2303466848 .stroke-AA2{stroke:#676C7E;} + .d2-2303466848 .stroke-AA4{stroke:#CFD2DD;} + .d2-2303466848 .stroke-AA5{stroke:#DEE1EB;} + .d2-2303466848 .stroke-AB4{stroke:#CFD2DD;} + .d2-2303466848 .stroke-AB5{stroke:#DEE1EB;} + .d2-2303466848 .background-color-N1{background-color:#0A0F25;} + .d2-2303466848 .background-color-N2{background-color:#676C7E;} + .d2-2303466848 .background-color-N3{background-color:#9499AB;} + .d2-2303466848 .background-color-N4{background-color:#CFD2DD;} + .d2-2303466848 .background-color-N5{background-color:#DEE1EB;} + .d2-2303466848 .background-color-N6{background-color:#EEF1F8;} + .d2-2303466848 .background-color-N7{background-color:#FFFFFF;} + .d2-2303466848 .background-color-B1{background-color:#0A0F25;} + .d2-2303466848 .background-color-B2{background-color:#676C7E;} + .d2-2303466848 .background-color-B3{background-color:#9499AB;} + .d2-2303466848 .background-color-B4{background-color:#CFD2DD;} + .d2-2303466848 .background-color-B5{background-color:#DEE1EB;} + .d2-2303466848 .background-color-B6{background-color:#EEF1F8;} + .d2-2303466848 .background-color-AA2{background-color:#676C7E;} + .d2-2303466848 .background-color-AA4{background-color:#CFD2DD;} + .d2-2303466848 .background-color-AA5{background-color:#DEE1EB;} + .d2-2303466848 .background-color-AB4{background-color:#CFD2DD;} + .d2-2303466848 .background-color-AB5{background-color:#DEE1EB;} + .d2-2303466848 .color-N1{color:#0A0F25;} + .d2-2303466848 .color-N2{color:#676C7E;} + .d2-2303466848 .color-N3{color:#9499AB;} + .d2-2303466848 .color-N4{color:#CFD2DD;} + .d2-2303466848 .color-N5{color:#DEE1EB;} + .d2-2303466848 .color-N6{color:#EEF1F8;} + .d2-2303466848 .color-N7{color:#FFFFFF;} + .d2-2303466848 .color-B1{color:#0A0F25;} + .d2-2303466848 .color-B2{color:#676C7E;} + .d2-2303466848 .color-B3{color:#9499AB;} + .d2-2303466848 .color-B4{color:#CFD2DD;} + .d2-2303466848 .color-B5{color:#DEE1EB;} + .d2-2303466848 .color-B6{color:#EEF1F8;} + .d2-2303466848 .color-AA2{color:#676C7E;} + .d2-2303466848 .color-AA4{color:#CFD2DD;} + .d2-2303466848 .color-AA5{color:#DEE1EB;} + .d2-2303466848 .color-AB4{color:#CFD2DD;} + .d2-2303466848 .color-AB5{color:#DEE1EB;}.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:#0A0F25;--color-border-muted:#676C7E;--color-neutral-muted:#EEF1F8;--color-accent-fg:#676C7E;--color-accent-emphasis:#676C7E;--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-dark);mix-blend-mode:overlay}.sketch-overlay-B3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-B4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.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-normal);mix-blend-mode:color-burn}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-AB5{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}.light-code{display: block}.dark-code{display: none}]]> @@ -104,7 +104,7 @@ -xyaitwasalli used to readdream +xyaitwasalli used to readdream diff --git a/e2etests/testdata/txtar.txt b/e2etests/testdata/txtar.txt index 9bf9b56db..fc009ca2b 100644 --- a/e2etests/testdata/txtar.txt +++ b/e2etests/testdata/txtar.txt @@ -47,3 +47,120 @@ without.tableEx -> with.tableEx without.classEx -> with.classEx without.codeEx -> with.codeEx without.mdEx -> with.mdEx + +-- theme-overrides -- + +direction: right +vars: { + d2-config: { + theme-overrides: { + B1: "#2E7D32" + B2: "#66BB6A" + B3: "#A5D6A7" + B4: "#C5E1A5" + B5: "#E6EE9C" + B6: "#FFF59D" + + AA2: "#0D47A1" + AA4: "#42A5F5" + AA5: "#90CAF9" + + AB4: "#F44336" + AB5: "#FFCDD2" + + N1: "#2E2E2E" + N2: "#2E2E2E" + N3: "#595959" + N4: "#858585" + N5: "#B1B1B1" + N6: "#DCDCDC" + N7: "#DCDCDC" + } + dark-theme-overrides: { + B1: "#2E7D32" + B2: "#66BB6A" + B3: "#A5D6A7" + B4: "#C5E1A5" + B5: "#E6EE9C" + B6: "#FFF59D" + + AA2: "#0D47A1" + AA4: "#42A5F5" + AA5: "#90CAF9" + + AB4: "#F44336" + AB5: "#FFCDD2" + + N1: "#2E2E2E" + N2: "#2E2E2E" + N3: "#595959" + N4: "#858585" + N5: "#B1B1B1" + N6: "#DCDCDC" + N7: "#DCDCDC" + } + } +} + +logs: { + shape: page + style.multiple: true +} +user: User {shape: person} +network: Network { + tower: Cell Tower { + satellites: { + shape: stored_data + style.multiple: true + } + + satellites -> transmitter + satellites -> transmitter + satellites -> transmitter + transmitter + } + processor: Data Processor { + storage: Storage { + shape: cylinder + style.multiple: true + } + } + portal: Online Portal { + UI + } + + tower.transmitter -> processor: phone logs +} +server: API Server + +user -> network.tower: Make call +network.processor -> server +network.processor -> server +network.processor -> server + +server -> logs +server -> logs +server -> logs: persist + +server -> network.portal.UI: display +user -> network.portal.UI: access { + style.stroke-dash: 3 +} + +costumes: { + shape: sql_table + id: int {constraint: primary_key} + silliness: int + monster: int + last_updated: timestamp +} + +monsters: { + shape: sql_table + id: int {constraint: primary_key} + movie: string + weight: int + last_updated: timestamp +} + +costumes.monster -> monsters.id diff --git a/e2etests/testdata/txtar/theme-overrides/dagre/board.exp.json b/e2etests/testdata/txtar/theme-overrides/dagre/board.exp.json new file mode 100644 index 000000000..f797e1f2b --- /dev/null +++ b/e2etests/testdata/txtar/theme-overrides/dagre/board.exp.json @@ -0,0 +1,1690 @@ +{ + "name": "", + "config": { + "sketch": null, + "themeID": null, + "darkThemeID": null, + "pad": null, + "center": null, + "layoutEngine": null, + "themeOverrides": { + "n1": "#2E2E2E", + "n2": "#2E2E2E", + "n3": "#595959", + "n4": "#858585", + "n5": "#B1B1B1", + "n6": "#DCDCDC", + "n7": "#DCDCDC", + "b1": "#2E7D32", + "b2": "#66BB6A", + "b3": "#A5D6A7", + "b4": "#C5E1A5", + "b5": "#E6EE9C", + "b6": "#FFF59D", + "aa2": "#0D47A1", + "aa4": "#42A5F5", + "aa5": "#90CAF9", + "ab4": "#F44336", + "ab5": "#FFCDD2" + }, + "darkThemeOverrides": { + "n1": "#2E2E2E", + "n2": "#2E2E2E", + "n3": "#595959", + "n4": "#858585", + "n5": "#B1B1B1", + "n6": "#DCDCDC", + "n7": "#DCDCDC", + "b1": "#2E7D32", + "b2": "#66BB6A", + "b3": "#A5D6A7", + "b4": "#C5E1A5", + "b5": "#E6EE9C", + "b6": "#FFF59D", + "aa2": "#0D47A1", + "aa4": "#42A5F5", + "aa5": "#90CAF9", + "ab4": "#F44336", + "ab5": "#FFCDD2" + } + }, + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "logs", + "type": "page", + "pos": { + "x": 2033, + "y": 10 + }, + "width": 73, + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 28, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "user", + "type": "person", + "pos": { + "x": 123, + "y": 470 + }, + "width": 48, + "height": 66, + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 33, + "labelHeight": 21, + "labelPosition": "OUTSIDE_BOTTOM_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "network", + "type": "rectangle", + "pos": { + "x": 606, + "y": 222 + }, + "width": 1553, + "height": 399, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B4", + "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": "Network", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 99, + "labelHeight": 36, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "network.tower", + "type": "rectangle", + "pos": { + "x": 636, + "y": 327 + }, + "width": 514, + "height": 143, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 106, + "labelHeight": 31, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "network.tower.satellites", + "type": "stored_data", + "pos": { + "x": 666, + "y": 371 + }, + "width": 130, + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 65, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "network.tower.transmitter", + "type": "rectangle", + "pos": { + "x": 992, + "y": 360 + }, + "width": 128, + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 83, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "network.processor", + "type": "rectangle", + "pos": { + "x": 1392, + "y": 263 + }, + "width": 171, + "height": 188, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 150, + "labelHeight": 31, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "network.processor.storage", + "type": "cylinder", + "pos": { + "x": 1422, + "y": 303 + }, + "width": 101, + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 56, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "network.portal", + "type": "rectangle", + "pos": { + "x": 2010, + "y": 465 + }, + "width": 119, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 132, + "labelHeight": 31, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "network.portal.UI", + "type": "rectangle", + "pos": { + "x": 2040, + "y": 495 + }, + "width": 59, + "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": "UI", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 14, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "server", + "type": "rectangle", + "pos": { + "x": 1694, + "y": 26 + }, + "width": 120, + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 75, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "costumes", + "type": "sql_table", + "pos": { + "x": 0, + "y": 712 + }, + "width": 294, + "height": 180, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "N1", + "stroke": "N7", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": [ + { + "name": { + "label": "id", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 15, + "labelHeight": 26 + }, + "type": { + "label": "int", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 23, + "labelHeight": 26 + }, + "constraint": [ + "primary_key" + ], + "reference": "" + }, + { + "name": { + "label": "silliness", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 66, + "labelHeight": 26 + }, + "type": { + "label": "int", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 23, + "labelHeight": 26 + }, + "constraint": null, + "reference": "" + }, + { + "name": { + "label": "monster", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 70, + "labelHeight": 26 + }, + "type": { + "label": "int", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 23, + "labelHeight": 26 + }, + "constraint": null, + "reference": "" + }, + { + "name": { + "label": "last_updated", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 110, + "labelHeight": 26 + }, + "type": { + "label": "timestamp", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 91, + "labelHeight": 26 + }, + "constraint": null, + "reference": "" + } + ], + "label": "costumes", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 101, + "labelHeight": 31, + "zIndex": 0, + "level": 1, + "primaryAccentColor": "B2", + "secondaryAccentColor": "AA2", + "neutralAccentColor": "N2" + }, + { + "id": "monsters", + "type": "sql_table", + "pos": { + "x": 584, + "y": 712 + }, + "width": 294, + "height": 180, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "N1", + "stroke": "N7", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": [ + { + "name": { + "label": "id", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 15, + "labelHeight": 26 + }, + "type": { + "label": "int", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 23, + "labelHeight": 26 + }, + "constraint": [ + "primary_key" + ], + "reference": "" + }, + { + "name": { + "label": "movie", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 51, + "labelHeight": 26 + }, + "type": { + "label": "string", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 48, + "labelHeight": 26 + }, + "constraint": null, + "reference": "" + }, + { + "name": { + "label": "weight", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 58, + "labelHeight": 26 + }, + "type": { + "label": "int", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 23, + "labelHeight": 26 + }, + "constraint": null, + "reference": "" + }, + { + "name": { + "label": "last_updated", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 110, + "labelHeight": 26 + }, + "type": { + "label": "timestamp", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 91, + "labelHeight": 26 + }, + "constraint": null, + "reference": "" + } + ], + "label": "monsters", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 99, + "labelHeight": 31, + "zIndex": 0, + "level": 1, + "primaryAccentColor": "B2", + "secondaryAccentColor": "AA2", + "neutralAccentColor": "N2" + } + ], + "connections": [ + { + "id": "network.tower.(satellites -> transmitter)[0]", + "src": "network.tower.satellites", + "srcArrow": "none", + "dst": "network.tower.transmitter", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 791, + "y": 393 + }, + { + "x": 906.2000122070312, + "y": 364.6000061035156 + }, + { + "x": 946.4000244140625, + "y": 362.8999938964844 + }, + { + "x": 992, + "y": 384.5 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "network.tower.(satellites -> transmitter)[1]", + "src": "network.tower.satellites", + "srcArrow": "none", + "dst": "network.tower.transmitter", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 792, + "y": 404 + }, + { + "x": 906.4000244140625, + "y": 404 + }, + { + "x": 946.4000244140625, + "y": 403.79998779296875 + }, + { + "x": 992, + "y": 403 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "network.tower.(satellites -> transmitter)[2]", + "src": "network.tower.satellites", + "srcArrow": "none", + "dst": "network.tower.transmitter", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 797, + "y": 416 + }, + { + "x": 907.4000244140625, + "y": 435.6000061035156 + }, + { + "x": 946.4000244140625, + "y": 436.8999938964844 + }, + { + "x": 992, + "y": 422.5 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "network.(tower.transmitter -> processor)[0]", + "src": "network.tower.transmitter", + "srcArrow": "none", + "dst": "network.processor", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "phone logs", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 74, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 1120, + "y": 392.75 + }, + { + "x": 1165.5999755859375, + "y": 392.75 + }, + { + "x": 1295.199951171875, + "y": 392.75 + }, + { + "x": 1392, + "y": 392.75 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(user -> network.tower)[0]", + "src": "user", + "srcArrow": "none", + "dst": "network.tower", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "Make call", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 62, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 163, + "y": 500 + }, + { + "x": 338.20001220703125, + "y": 415.20001220703125 + }, + { + "x": 503.20001220703125, + "y": 394 + }, + { + "x": 636, + "y": 394 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(network.processor -> server)[0]", + "src": "network.processor", + "srcArrow": "none", + "dst": "server", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1563, + "y": 312.25 + }, + { + "x": 1622.199951171875, + "y": 312.25 + }, + { + "x": 1655.800048828125, + "y": 268.25 + }, + { + "x": 1731, + "y": 92.25 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(network.processor -> server)[1]", + "src": "network.processor", + "srcArrow": "none", + "dst": "server", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1563, + "y": 351.75 + }, + { + "x": 1622.199951171875, + "y": 351.75 + }, + { + "x": 1656.5999755859375, + "y": 299.75 + }, + { + "x": 1735, + "y": 91.75 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(network.processor -> server)[2]", + "src": "network.processor", + "srcArrow": "none", + "dst": "server", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1563, + "y": 401.25 + }, + { + "x": 1622.199951171875, + "y": 401.25 + }, + { + "x": 1657.4000244140625, + "y": 339.45001220703125 + }, + { + "x": 1739, + "y": 92.25 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(server -> logs)[0]", + "src": "server", + "srcArrow": "none", + "dst": "logs", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1814, + "y": 45.5 + }, + { + "x": 1878.800048828125, + "y": 31.899999618530273 + }, + { + "x": 1987.4000244140625, + "y": 31.399999618530273 + }, + { + "x": 2033, + "y": 43 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(server -> logs)[1]", + "src": "server", + "srcArrow": "none", + "dst": "logs", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1814, + "y": 54.5 + }, + { + "x": 1878.800048828125, + "y": 49.70000076293945 + }, + { + "x": 1987.4000244140625, + "y": 49.20000076293945 + }, + { + "x": 2033, + "y": 52 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(server -> logs)[2]", + "src": "server", + "srcArrow": "none", + "dst": "logs", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "persist", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 46, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 1814, + "y": 72 + }, + { + "x": 1878.800048828125, + "y": 85.5999984741211 + }, + { + "x": 1987.4000244140625, + "y": 84.5999984741211 + }, + { + "x": 2033, + "y": 67 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(server -> network.portal.UI)[0]", + "src": "server", + "srcArrow": "none", + "dst": "network.portal.UI", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "display", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 48, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 1771, + "y": 91.75 + }, + { + "x": 1870.199951171875, + "y": 426.1499938964844 + }, + { + "x": 1988.800048828125, + "y": 512.1500244140625 + }, + { + "x": 2040, + "y": 521.75 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(user -> network.portal.UI)[0]", + "src": "user", + "srcArrow": "none", + "dst": "network.portal.UI", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 3, + "strokeWidth": 2, + "stroke": "B2", + "borderRadius": 10, + "label": "access", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 44, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 161, + "y": 505 + }, + { + "x": 337.79998779296875, + "y": 568 + }, + { + "x": 399.6000061035156, + "y": 583.75 + }, + { + "x": 426, + "y": 583.75 + }, + { + "x": 452.3999938964844, + "y": 583.75 + }, + { + "x": 481.3999938964844, + "y": 583.75 + }, + { + "x": 498.5, + "y": 583.75 + }, + { + "x": 515.5999755859375, + "y": 583.75 + }, + { + "x": 567.7999877929688, + "y": 583.75 + }, + { + "x": 629, + "y": 583.75 + }, + { + "x": 690.2000122070312, + "y": 583.75 + }, + { + "x": 771.7999877929688, + "y": 583.75 + }, + { + "x": 833, + "y": 583.75 + }, + { + "x": 894.2000122070312, + "y": 583.75 + }, + { + "x": 959.2000122070312, + "y": 583.75 + }, + { + "x": 995.5, + "y": 583.75 + }, + { + "x": 1031.800048828125, + "y": 583.75 + }, + { + "x": 1080.199951171875, + "y": 583.75 + }, + { + "x": 1116.5, + "y": 583.75 + }, + { + "x": 1152.800048828125, + "y": 583.75 + }, + { + "x": 1195.800048828125, + "y": 583.75 + }, + { + "x": 1224, + "y": 583.75 + }, + { + "x": 1252.199951171875, + "y": 583.75 + }, + { + "x": 1289.800048828125, + "y": 583.75 + }, + { + "x": 1318, + "y": 583.75 + }, + { + "x": 1346.199951171875, + "y": 583.75 + }, + { + "x": 1386.5, + "y": 583.75 + }, + { + "x": 1418.75, + "y": 583.75 + }, + { + "x": 1451, + "y": 583.75 + }, + { + "x": 1494, + "y": 583.75 + }, + { + "x": 1526.25, + "y": 583.75 + }, + { + "x": 1558.5, + "y": 583.75 + }, + { + "x": 1591.4000244140625, + "y": 583.75 + }, + { + "x": 1608.5, + "y": 583.75 + }, + { + "x": 1625.5999755859375, + "y": 583.75 + }, + { + "x": 1660.4000244140625, + "y": 583.75 + }, + { + "x": 1695.5, + "y": 583.75 + }, + { + "x": 1730.5999755859375, + "y": 583.75 + }, + { + "x": 1782.199951171875, + "y": 583.75 + }, + { + "x": 1824.5, + "y": 583.75 + }, + { + "x": 1866.800048828125, + "y": 583.75 + }, + { + "x": 1988.800048828125, + "y": 574.1500244140625 + }, + { + "x": 2040, + "y": 535.75 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(costumes -> monsters)[0]", + "src": "costumes", + "srcArrow": "none", + "dst": "monsters", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 294, + "y": 801.5 + }, + { + "x": 364.3999938964844, + "y": 801.5 + }, + { + "x": 399.6000061035156, + "y": 801.5 + }, + { + "x": 426, + "y": 801.5 + }, + { + "x": 452.3999938964844, + "y": 801.5 + }, + { + "x": 538.4000244140625, + "y": 801.5 + }, + { + "x": 584, + "y": 801.5 + } + ], + "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/txtar/theme-overrides/dagre/sketch.exp.svg b/e2etests/testdata/txtar/theme-overrides/dagre/sketch.exp.svg new file mode 100644 index 000000000..37f43a988 --- /dev/null +++ b/e2etests/testdata/txtar/theme-overrides/dagre/sketch.exp.svg @@ -0,0 +1,124 @@ +logsUserNetworkAPI ServercostumesidintPKsillinessintmonsterintlast_updatedtimestampmonstersidintPKmoviestringweightintlast_updatedtimestampCell TowerData ProcessorOnline PortalsatellitestransmitterStorageUI phone logsMake callpersistdisplay access + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/e2etests/testdata/txtar/theme-overrides/elk/board.exp.json b/e2etests/testdata/txtar/theme-overrides/elk/board.exp.json new file mode 100644 index 000000000..44705ad31 --- /dev/null +++ b/e2etests/testdata/txtar/theme-overrides/elk/board.exp.json @@ -0,0 +1,1468 @@ +{ + "name": "", + "config": { + "sketch": null, + "themeID": null, + "darkThemeID": null, + "pad": null, + "center": null, + "layoutEngine": null, + "themeOverrides": { + "n1": "#2E2E2E", + "n2": "#2E2E2E", + "n3": "#595959", + "n4": "#858585", + "n5": "#B1B1B1", + "n6": "#DCDCDC", + "n7": "#DCDCDC", + "b1": "#2E7D32", + "b2": "#66BB6A", + "b3": "#A5D6A7", + "b4": "#C5E1A5", + "b5": "#E6EE9C", + "b6": "#FFF59D", + "aa2": "#0D47A1", + "aa4": "#42A5F5", + "aa5": "#90CAF9", + "ab4": "#F44336", + "ab5": "#FFCDD2" + }, + "darkThemeOverrides": { + "n1": "#2E2E2E", + "n2": "#2E2E2E", + "n3": "#595959", + "n4": "#858585", + "n5": "#B1B1B1", + "n6": "#DCDCDC", + "n7": "#DCDCDC", + "b1": "#2E7D32", + "b2": "#66BB6A", + "b3": "#A5D6A7", + "b4": "#C5E1A5", + "b5": "#E6EE9C", + "b6": "#FFF59D", + "aa2": "#0D47A1", + "aa4": "#42A5F5", + "aa5": "#90CAF9", + "ab4": "#F44336", + "ab5": "#FFCDD2" + } + }, + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "logs", + "type": "page", + "pos": { + "x": 2284, + "y": 321 + }, + "width": 73, + "height": 120, + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 28, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "user", + "type": "person", + "pos": { + "x": 258, + "y": 276 + }, + "width": 48, + "height": 80, + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 33, + "labelHeight": 21, + "labelPosition": "OUTSIDE_BOTTOM_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "network", + "type": "rectangle", + "pos": { + "x": 765, + "y": 103 + }, + "width": 978, + "height": 530, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B4", + "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": "Network", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 99, + "labelHeight": 36, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "network.tower", + "type": "rectangle", + "pos": { + "x": 815, + "y": 153 + }, + "width": 448, + "height": 230, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 106, + "labelHeight": 31, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "network.tower.satellites", + "type": "stored_data", + "pos": { + "x": 865, + "y": 213 + }, + "width": 130, + "height": 120, + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 65, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "network.tower.transmitter", + "type": "rectangle", + "pos": { + "x": 1085, + "y": 208 + }, + "width": 128, + "height": 120, + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 83, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "network.processor", + "type": "rectangle", + "pos": { + "x": 1482, + "y": 154 + }, + "width": 211, + "height": 228, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 150, + "labelHeight": 31, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "network.processor.storage", + "type": "cylinder", + "pos": { + "x": 1532, + "y": 214 + }, + "width": 101, + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 56, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "network.portal", + "type": "rectangle", + "pos": { + "x": 820, + "y": 403 + }, + "width": 177, + "height": 180, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B5", + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 132, + "labelHeight": 31, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "network.portal.UI", + "type": "rectangle", + "pos": { + "x": 879, + "y": 453 + }, + "width": 59, + "height": 80, + "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": "UI", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 14, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "server", + "type": "rectangle", + "pos": { + "x": 1958, + "y": 296 + }, + "width": 120, + "height": 160, + "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": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 75, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "costumes", + "type": "sql_table", + "pos": { + "x": 12, + "y": 12 + }, + "width": 294, + "height": 180, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "N1", + "stroke": "N7", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": [ + { + "name": { + "label": "id", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 15, + "labelHeight": 26 + }, + "type": { + "label": "int", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 23, + "labelHeight": 26 + }, + "constraint": [ + "primary_key" + ], + "reference": "" + }, + { + "name": { + "label": "silliness", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 66, + "labelHeight": 26 + }, + "type": { + "label": "int", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 23, + "labelHeight": 26 + }, + "constraint": null, + "reference": "" + }, + { + "name": { + "label": "monster", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 70, + "labelHeight": 26 + }, + "type": { + "label": "int", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 23, + "labelHeight": 26 + }, + "constraint": null, + "reference": "" + }, + { + "name": { + "label": "last_updated", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 110, + "labelHeight": 26 + }, + "type": { + "label": "timestamp", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 91, + "labelHeight": 26 + }, + "constraint": null, + "reference": "" + } + ], + "label": "costumes", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 101, + "labelHeight": 31, + "zIndex": 0, + "level": 1, + "primaryAccentColor": "B2", + "secondaryAccentColor": "AA2", + "neutralAccentColor": "N2" + }, + { + "id": "monsters", + "type": "sql_table", + "pos": { + "x": 386, + "y": 84 + }, + "width": 294, + "height": 180, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "N1", + "stroke": "N7", + "shadow": false, + "3d": false, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": [ + { + "name": { + "label": "id", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 15, + "labelHeight": 26 + }, + "type": { + "label": "int", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 23, + "labelHeight": 26 + }, + "constraint": [ + "primary_key" + ], + "reference": "" + }, + { + "name": { + "label": "movie", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 51, + "labelHeight": 26 + }, + "type": { + "label": "string", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 48, + "labelHeight": 26 + }, + "constraint": null, + "reference": "" + }, + { + "name": { + "label": "weight", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 58, + "labelHeight": 26 + }, + "type": { + "label": "int", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 23, + "labelHeight": 26 + }, + "constraint": null, + "reference": "" + }, + { + "name": { + "label": "last_updated", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 110, + "labelHeight": 26 + }, + "type": { + "label": "timestamp", + "fontSize": 0, + "fontFamily": "", + "language": "", + "color": "", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 91, + "labelHeight": 26 + }, + "constraint": null, + "reference": "" + } + ], + "label": "monsters", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 99, + "labelHeight": 31, + "zIndex": 0, + "level": 1, + "primaryAccentColor": "B2", + "secondaryAccentColor": "AA2", + "neutralAccentColor": "N2" + } + ], + "connections": [ + { + "id": "network.tower.(satellites -> transmitter)[0]", + "src": "network.tower.satellites", + "srcArrow": "none", + "dst": "network.tower.transmitter", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 985, + "y": 239 + }, + { + "x": 1085, + "y": 238.5 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "network.tower.(satellites -> transmitter)[1]", + "src": "network.tower.satellites", + "srcArrow": "none", + "dst": "network.tower.transmitter", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 990, + "y": 269 + }, + { + "x": 1085, + "y": 268 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "network.tower.(satellites -> transmitter)[2]", + "src": "network.tower.satellites", + "srcArrow": "none", + "dst": "network.tower.transmitter", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 982, + "y": 299 + }, + { + "x": 1085, + "y": 298.5 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "network.(tower.transmitter -> processor)[0]", + "src": "network.tower.transmitter", + "srcArrow": "none", + "dst": "network.processor", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "phone logs", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 74, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 1213, + "y": 268.5 + }, + { + "x": 1482, + "y": 268.5 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(user -> network.tower)[0]", + "src": "user", + "srcArrow": "none", + "dst": "network.tower", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "Make call", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 62, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 299, + "y": 295 + }, + { + "x": 815, + "y": 295 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(network.processor -> server)[0]", + "src": "network.processor", + "srcArrow": "none", + "dst": "server", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1693, + "y": 222.25 + }, + { + "x": 1918, + "y": 222.25 + }, + { + "x": 1918, + "y": 328 + }, + { + "x": 1958, + "y": 328 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(network.processor -> server)[1]", + "src": "network.processor", + "srcArrow": "none", + "dst": "server", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1693, + "y": 268.5 + }, + { + "x": 1868, + "y": 268.5 + }, + { + "x": 1868, + "y": 360 + }, + { + "x": 1958, + "y": 360 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(network.processor -> server)[2]", + "src": "network.processor", + "srcArrow": "none", + "dst": "server", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 1693, + "y": 325.5 + }, + { + "x": 1788, + "y": 325.5 + }, + { + "x": 1788, + "y": 404.5 + }, + { + "x": 1868, + "y": 404.5 + }, + { + "x": 1868, + "y": 392 + }, + { + "x": 1958, + "y": 392 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(server -> logs)[0]", + "src": "server", + "srcArrow": "none", + "dst": "logs", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 2078, + "y": 339.75 + }, + { + "x": 2244, + "y": 339.75 + }, + { + "x": 2244, + "y": 343.5 + }, + { + "x": 2284, + "y": 343 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(server -> logs)[1]", + "src": "server", + "srcArrow": "none", + "dst": "logs", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 2078, + "y": 376 + }, + { + "x": 2284, + "y": 376 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(server -> logs)[2]", + "src": "server", + "srcArrow": "none", + "dst": "logs", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "persist", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 46, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 2078, + "y": 428 + }, + { + "x": 2244, + "y": 428 + }, + { + "x": 2244, + "y": 408.5 + }, + { + "x": 2284, + "y": 408 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(server -> network.portal.UI)[0]", + "src": "server", + "srcArrow": "none", + "dst": "network.portal.UI", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "display", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 48, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 1958, + "y": 424 + }, + { + "x": 1918, + "y": 424 + }, + { + "x": 1918, + "y": 664.5 + }, + { + "x": 720, + "y": 664.5 + }, + { + "x": 720, + "y": 506.8330078125 + }, + { + "x": 879, + "y": 506.8330078125 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(user -> network.portal.UI)[0]", + "src": "user", + "srcArrow": "none", + "dst": "network.portal.UI", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 3, + "strokeWidth": 2, + "stroke": "B2", + "borderRadius": 10, + "label": "access", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 44, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 306, + "y": 347 + }, + { + "x": 720, + "y": 347.25 + }, + { + "x": 720, + "y": 480.1659851074219 + }, + { + "x": 879, + "y": 480.1659851074219 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(costumes -> monsters)[0]", + "src": "costumes", + "srcArrow": "none", + "dst": "monsters", + "dstArrow": "triangle", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "borderRadius": 10, + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 306, + "y": 138 + }, + { + "x": 386, + "y": 138 + } + ], + "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/txtar/theme-overrides/elk/sketch.exp.svg b/e2etests/testdata/txtar/theme-overrides/elk/sketch.exp.svg new file mode 100644 index 000000000..abd5046b0 --- /dev/null +++ b/e2etests/testdata/txtar/theme-overrides/elk/sketch.exp.svg @@ -0,0 +1,124 @@ +logsUserNetworkAPI ServercostumesidintPKsillinessintmonsterintlast_updatedtimestampmonstersidintPKmoviestringweightintlast_updatedtimestampCell TowerData ProcessorOnline PortalsatellitestransmitterStorageUI phone logsMake callpersistdisplay access + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/color/color.go b/lib/color/color.go index 7a54573e6..7a7a4d9c1 100644 --- a/lib/color/color.go +++ b/lib/color/color.go @@ -348,3 +348,158 @@ func Name2RGB(name string) RGB { } return RGB{} } + +var NamedColors = []string{ + "currentcolor", + "transparent", + "aliceblue", + "antiquewhite", + "aqua", + "aquamarine", + "azure", + "beige", + "bisque", + "black", + "blanchedalmond", + "blue", + "blueviolet", + "brown", + "burlywood", + "cadetblue", + "chartreuse", + "chocolate", + "coral", + "cornflowerblue", + "cornsilk", + "crimson", + "cyan", + "darkblue", + "darkcyan", + "darkgoldenrod", + "darkgray", + "darkgrey", + "darkgreen", + "darkkhaki", + "darkmagenta", + "darkolivegreen", + "darkorange", + "darkorchid", + "darkred", + "darksalmon", + "darkseagreen", + "darkslateblue", + "darkslategray", + "darkslategrey", + "darkturquoise", + "darkviolet", + "deeppink", + "deepskyblue", + "dimgray", + "dimgrey", + "dodgerblue", + "firebrick", + "floralwhite", + "forestgreen", + "fuchsia", + "gainsboro", + "ghostwhite", + "gold", + "goldenrod", + "gray", + "grey", + "green", + "greenyellow", + "honeydew", + "hotpink", + "indianred", + "indigo", + "ivory", + "khaki", + "lavender", + "lavenderblush", + "lawngreen", + "lemonchiffon", + "lightblue", + "lightcoral", + "lightcyan", + "lightgoldenrodyellow", + "lightgray", + "lightgrey", + "lightgreen", + "lightpink", + "lightsalmon", + "lightseagreen", + "lightskyblue", + "lightslategray", + "lightslategrey", + "lightsteelblue", + "lightyellow", + "lime", + "limegreen", + "linen", + "magenta", + "maroon", + "mediumaquamarine", + "mediumblue", + "mediumorchid", + "mediumpurple", + "mediumseagreen", + "mediumslateblue", + "mediumspringgreen", + "mediumturquoise", + "mediumvioletred", + "midnightblue", + "mintcream", + "mistyrose", + "moccasin", + "navajowhite", + "navy", + "oldlace", + "olive", + "olivedrab", + "orange", + "orangered", + "orchid", + "palegoldenrod", + "palegreen", + "paleturquoise", + "palevioletred", + "papayawhip", + "peachpuff", + "peru", + "pink", + "plum", + "powderblue", + "purple", + "rebeccapurple", + "red", + "rosybrown", + "royalblue", + "saddlebrown", + "salmon", + "sandybrown", + "seagreen", + "seashell", + "sienna", + "silver", + "skyblue", + "slateblue", + "slategray", + "slategrey", + "snow", + "springgreen", + "steelblue", + "tan", + "teal", + "thistle", + "tomato", + "turquoise", + "violet", + "wheat", + "white", + "whitesmoke", + "yellow", + "yellowgreen", +} + +var ColorHexRegex = regexp.MustCompile(`^#(([0-9a-fA-F]{2}){3}|([0-9a-fA-F]){3})$`) diff --git a/testdata/d2compiler/TestCompile/var-not-color.exp.json b/testdata/d2compiler/TestCompile/var-not-color.exp.json new file mode 100644 index 000000000..8b6feccbf --- /dev/null +++ b/testdata/d2compiler/TestCompile/var-not-color.exp.json @@ -0,0 +1,15 @@ +{ + "graph": null, + "err": { + "errs": [ + { + "range": "d2/testdata/d2compiler/TestCompile/var-not-color.d2,3:6:52-3:16:62", + "errmsg": "d2/testdata/d2compiler/TestCompile/var-not-color.d2:4:7: expected \"B1\" to be a valid named color (\"orange\") or a hex code (\"#f0ff3a\")" + }, + { + "range": "d2/testdata/d2compiler/TestCompile/var-not-color.d2,4:3:66-4:13:76", + "errmsg": "d2/testdata/d2compiler/TestCompile/var-not-color.d2:5:4: \"potato\" is not a valid theme code" + } + ] + } +}