diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index ff0cbf2da..28e0ab2af 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -8,6 +8,7 @@ #### Improvements 🧹 - `d2 fmt` now preserves leading comment spacing. [#400](https://github.com/terrastruct/d2/issues/400) +- Markdown can now be styled with keywords stroke and fill. [https://github.com/terrastruct/d2/pull/460](https://github.com/terrastruct/d2/pull/460) #### Bugfixes ⛑️ diff --git a/d2exporter/export.go b/d2exporter/export.go index 96900ff01..952a85662 100644 --- a/d2exporter/export.go +++ b/d2exporter/export.go @@ -45,6 +45,8 @@ func applyStyles(shape *d2target.Shape, obj *d2graph.Object) { } if obj.Attributes.Style.Fill != nil { shape.Fill = obj.Attributes.Style.Fill.Value + } else if obj.Attributes.Shape.Value == d2target.ShapeText { + shape.Fill = "transparent" } if obj.Attributes.Style.Stroke != nil { shape.Stroke = obj.Attributes.Style.Stroke.Value diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index 838ffe6d7..528df55c1 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -397,7 +397,10 @@ func (obj *Object) GetFill(theme *d2themes.Theme) string { func (obj *Object) GetStroke(theme *d2themes.Theme, dashGapSize interface{}) string { shape := obj.Attributes.Shape.Value - if strings.EqualFold(shape, d2target.ShapeCode) || strings.EqualFold(shape, d2target.ShapeClass) || strings.EqualFold(shape, d2target.ShapeSQLTable) { + if strings.EqualFold(shape, d2target.ShapeCode) || + strings.EqualFold(shape, d2target.ShapeClass) || + strings.EqualFold(shape, d2target.ShapeSQLTable) || + strings.EqualFold(shape, d2target.ShapeText) { return theme.Colors.Neutrals.N1 } if dashGapSize != 0.0 { diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go index db5b650bc..41a0c63a6 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -770,7 +770,16 @@ func drawShape(writer io.Writer, targetShape d2target.Shape) (labelMask string, ) // we need the self closing form in this svg/xhtml context render = strings.ReplaceAll(render, "
", "
") - fmt.Fprintf(writer, `
%v
`, render) + + var mdStyle string + if targetShape.Fill != "" { + mdStyle = fmt.Sprintf("background-color:%s;", targetShape.Fill) + } + if targetShape.Stroke != "" { + mdStyle += fmt.Sprintf("color:%s;", targetShape.Stroke) + } + + fmt.Fprintf(writer, `
%v
`, mdStyle, render) fmt.Fprint(writer, ``) } default: diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go index be9381938..76f4cf12a 100644 --- a/e2etests/stable_test.go +++ b/e2etests/stable_test.go @@ -1483,6 +1483,36 @@ a.note: "just\na\nlong\nnote\nhere"`, script: `shape: sequence_diagram alice -> bob: what does it mean to be well-adjusted bob -> alice: The ability to play bridge or golf as if they were games +`, + }, + { + name: "markdown_stroke_fill", + script: ` +container.md: |md +# a header + +a line of text and an + + { + indented: "block", + of: "json", + } + +walk into a bar. +| { + style.stroke: darkorange +} + +container -> no container + +no container: |md +they did it in style +| + +no container.style: { + stroke: red + fill: "#CEEDEE" +} `, }, } diff --git a/e2etests/testdata/stable/chaos2/dagre/board.exp.json b/e2etests/testdata/stable/chaos2/dagre/board.exp.json index c928b6a24..79dbd4512 100644 --- a/e2etests/testdata/stable/chaos2/dagre/board.exp.json +++ b/e2etests/testdata/stable/chaos2/dagre/board.exp.json @@ -174,8 +174,8 @@ "strokeDash": 0, "strokeWidth": 2, "borderRadius": 0, - "fill": "#FFFFFF", - "stroke": "#0D32B2", + "fill": "transparent", + "stroke": "#0A0F25", "shadow": false, "3d": false, "multiple": false, @@ -253,8 +253,8 @@ "strokeDash": 0, "strokeWidth": 2, "borderRadius": 0, - "fill": "#FFFFFF", - "stroke": "#0D32B2", + "fill": "transparent", + "stroke": "#0A0F25", "shadow": false, "3d": false, "multiple": false, @@ -532,8 +532,8 @@ "strokeDash": 0, "strokeWidth": 2, "borderRadius": 0, - "fill": "#FFFFFF", - "stroke": "#0D32B2", + "fill": "transparent", + "stroke": "#0A0F25", "shadow": false, "3d": false, "multiple": false, diff --git a/e2etests/testdata/stable/chaos2/dagre/sketch.exp.svg b/e2etests/testdata/stable/chaos2/dagre/sketch.exp.svg index f29093782..ef295905d 100644 --- a/e2etests/testdata/stable/chaos2/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/chaos2/dagre/sketch.exp.svg @@ -774,10 +774,10 @@ width="1317" height="1854" viewBox="-100 -100 1317 1854">aabbllmm

nn

-
oocciikkdd

gg

-
hhjj

ee

-
ff1122 334455667788 +aabbllmm

nn

+
oocciikkdd

gg

+
hhjj

ee

+
ff1122 334455667788 diff --git a/e2etests/testdata/stable/chaos2/elk/board.exp.json b/e2etests/testdata/stable/chaos2/elk/board.exp.json index 5d02a2fb0..f99715058 100644 --- a/e2etests/testdata/stable/chaos2/elk/board.exp.json +++ b/e2etests/testdata/stable/chaos2/elk/board.exp.json @@ -174,8 +174,8 @@ "strokeDash": 0, "strokeWidth": 2, "borderRadius": 0, - "fill": "#FFFFFF", - "stroke": "#0D32B2", + "fill": "transparent", + "stroke": "#0A0F25", "shadow": false, "3d": false, "multiple": false, @@ -253,8 +253,8 @@ "strokeDash": 0, "strokeWidth": 2, "borderRadius": 0, - "fill": "#FFFFFF", - "stroke": "#0D32B2", + "fill": "transparent", + "stroke": "#0A0F25", "shadow": false, "3d": false, "multiple": false, @@ -532,8 +532,8 @@ "strokeDash": 0, "strokeWidth": 2, "borderRadius": 0, - "fill": "#FFFFFF", - "stroke": "#0D32B2", + "fill": "transparent", + "stroke": "#0A0F25", "shadow": false, "3d": false, "multiple": false, diff --git a/e2etests/testdata/stable/chaos2/elk/sketch.exp.svg b/e2etests/testdata/stable/chaos2/elk/sketch.exp.svg index 5cc89bc23..96c477b53 100644 --- a/e2etests/testdata/stable/chaos2/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/chaos2/elk/sketch.exp.svg @@ -774,10 +774,10 @@ width="1092" height="1907" viewBox="-88 -88 1092 1907">aabbllmm

nn

-
oocciikkdd

gg

-
hhjj

ee

-
ff1122 334455667788 +aabbllmm

nn

+
oocciikkdd

gg

+
hhjj

ee

+
ff1122 334455667788 diff --git a/e2etests/testdata/stable/giant_markdown_test/dagre/board.exp.json b/e2etests/testdata/stable/giant_markdown_test/dagre/board.exp.json index 62256201b..414bc5f4a 100644 --- a/e2etests/testdata/stable/giant_markdown_test/dagre/board.exp.json +++ b/e2etests/testdata/stable/giant_markdown_test/dagre/board.exp.json @@ -14,8 +14,8 @@ "strokeDash": 0, "strokeWidth": 2, "borderRadius": 0, - "fill": "#FFFFFF", - "stroke": "#0D32B2", + "fill": "transparent", + "stroke": "#0A0F25", "shadow": false, "3d": false, "multiple": false, diff --git a/e2etests/testdata/stable/giant_markdown_test/dagre/sketch.exp.svg b/e2etests/testdata/stable/giant_markdown_test/dagre/sketch.exp.svg index 920493c11..14fc3e202 100644 --- a/e2etests/testdata/stable/giant_markdown_test/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/giant_markdown_test/dagre/sketch.exp.svg @@ -774,7 +774,7 @@ width="3251" height="5500" viewBox="-100 -100 3251 5500">

Markdown: Syntax

+

Markdown: Syntax

  • Overview
      @@ -1031,7 +1031,7 @@ title for the link, surrounded in quotes. For example:

      Code

      Unlike a pre-formatted code block, a code span indicates code within a normal paragraph. For example:

      -
ab +
ab

Markdown: Syntax

+

Markdown: Syntax

  • Overview
      @@ -1031,7 +1031,7 @@ title for the link, surrounded in quotes. For example:

      Code

      Unlike a pre-formatted code block, a code span indicates code within a normal paragraph. For example:

      -
ab +
ab

Note: This document is itself written using Markdown; you +

Note: This document is itself written using Markdown; you can see the source for it by adding '.text' to the URL.


Overview

-
ab +
ab

Note: This document is itself written using Markdown; you +

Note: This document is itself written using Markdown; you can see the source for it by adding '.text' to the URL.


Overview

-
ab +
ab mixed togethersugarsolution we get +mixed togethersugarsolution we get mixed togethersugarsolution we get +mixed togethersugarsolution we get
    +
    • Overview
      • Philosophy
      • @@ -786,7 +786,7 @@ width="579" height="752" viewBox="-100 -100 579 752">
          +
          • Overview
            • Philosophy
            • @@ -786,7 +786,7 @@ width="579" height="752" viewBox="-88 -88 579 752">
                +
                • Overview ok this is all measured
                  • Philosophy
                  • @@ -782,7 +782,7 @@ width="445" height="728" viewBox="-100 -100 445 728">
                      +
                      • Overview ok this is all measured
                        • Philosophy
                        • @@ -782,7 +782,7 @@ width="445" height="728" viewBox="-88 -88 445 728">
                            +
                            • Overview
                              • Philosophy
                              • @@ -807,7 +807,7 @@ width="547" height="1164" viewBox="-100 -100 547 1164">
                                  +
                                  • Overview
                                    • Philosophy
                                    • @@ -807,7 +807,7 @@ width="547" height="1164" viewBox="-88 -88 547 1164">

                                      List items may consist of multiple paragraphs. Each subsequent +

                                      List items may consist of multiple paragraphs. Each subsequent paragraph in a list item must be indented by either 4 spaces or one tab:

                                        @@ -805,7 +805,7 @@ sit amet, consectetuer adipiscing elit.

                                        Another item in the same list.

                                    -
                                  ab +
                                ab

                                List items may consist of multiple paragraphs. Each subsequent +

                                List items may consist of multiple paragraphs. Each subsequent paragraph in a list item must be indented by either 4 spaces or one tab:

                                  @@ -805,7 +805,7 @@ sit amet, consectetuer adipiscing elit.

                                  Another item in the same list.

                              -
                            ab +
                          ab

                          Markdown: Syntax

                          -
                          ab +

                          Markdown: Syntax

                          +
                          ab

                          Markdown: Syntax

                          -
                          ab +

                          Markdown: Syntax

                          +
                          ab

                          Every frustum longs to be a cone

                          +

                          Every frustum longs to be a cone

                          • A continuing flow of paper is sufficient to continue the flow of paper
                          • Please remain calm, it's no use both of us being hysterical at the same time
                          • Visits always give pleasure: if not on arrival, then on the departure

                          Festivity Level 1: Your guests are chatting amiably with each other.

                          -
                          xy +
                          xy

                          Every frustum longs to be a cone

                          +

                          Every frustum longs to be a cone

                          • A continuing flow of paper is sufficient to continue the flow of paper
                          • Please remain calm, it's no use both of us being hysterical at the same time
                          • Visits always give pleasure: if not on arrival, then on the departure

                          Festivity Level 1: Your guests are chatting amiably with each other.

                          -
                          xy +
                          xy container

                          they did it in style

                          +

                          a header

                          +

                          a line of text and an

                          +
                          {
                          +	indented: "block",
                          +	of: "json",
                          +}
                          +
                          +

                          walk into a bar.

                          +
                          + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/markdown_stroke_fill/elk/board.exp.json b/e2etests/testdata/stable/markdown_stroke_fill/elk/board.exp.json new file mode 100644 index 000000000..197eecbbb --- /dev/null +++ b/e2etests/testdata/stable/markdown_stroke_fill/elk/board.exp.json @@ -0,0 +1,164 @@ +{ + "name": "", + "shapes": [ + { + "id": "container", + "type": "", + "pos": { + "x": 12, + "y": 12 + }, + "width": 362, + "height": 407, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#E3E9FD", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "container", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 117, + "labelHeight": 41, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "container.md", + "type": "text", + "pos": { + "x": 87, + "y": 87 + }, + "width": 212, + "height": 257, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "transparent", + "stroke": "darkorange", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "# a header\n\na line of text and an\n\n\t{\n\t\tindented: \"block\",\n\t\tof: \"json\",\n\t}\n\nwalk into a bar.", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "markdown", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 212, + "labelHeight": 257, + "zIndex": 0, + "level": 2 + }, + { + "id": "no container", + "type": "text", + "pos": { + "x": 134, + "y": 519 + }, + "width": 118, + "height": 24, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#CEEDEE", + "stroke": "red", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "they did it in style", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "markdown", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 118, + "labelHeight": 24, + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(container -> no container)[0]", + "src": "container", + "srcArrow": "none", + "srcLabel": "", + "dst": "no container", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 193, + "y": 419 + }, + { + "x": 193, + "y": 519 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/stable/markdown_stroke_fill/elk/sketch.exp.svg b/e2etests/testdata/stable/markdown_stroke_fill/elk/sketch.exp.svg new file mode 100644 index 000000000..d57478e16 --- /dev/null +++ b/e2etests/testdata/stable/markdown_stroke_fill/elk/sketch.exp.svg @@ -0,0 +1,803 @@ + +container

                          they did it in style

                          +

                          a header

                          +

                          a line of text and an

                          +
                          {
                          +	indented: "block",
                          +	of: "json",
                          +}
                          +
                          +

                          walk into a bar.

                          +
                          + + +
                          \ No newline at end of file diff --git a/e2etests/testdata/stable/md_2space_newline/dagre/board.exp.json b/e2etests/testdata/stable/md_2space_newline/dagre/board.exp.json index 994095495..21a05248c 100644 --- a/e2etests/testdata/stable/md_2space_newline/dagre/board.exp.json +++ b/e2etests/testdata/stable/md_2space_newline/dagre/board.exp.json @@ -54,8 +54,8 @@ "strokeDash": 0, "strokeWidth": 2, "borderRadius": 0, - "fill": "#FFFFFF", - "stroke": "#0D32B2", + "fill": "transparent", + "stroke": "#0A0F25", "shadow": false, "3d": false, "multiple": false, diff --git a/e2etests/testdata/stable/md_2space_newline/dagre/sketch.exp.svg b/e2etests/testdata/stable/md_2space_newline/dagre/sketch.exp.svg index e304bd6a9..1e8e6f874 100644 --- a/e2etests/testdata/stable/md_2space_newline/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/md_2space_newline/dagre/sketch.exp.svg @@ -774,9 +774,9 @@ width="759" height="348" viewBox="-100 -100 759 348">markdown

                          Lorem ipsum dolor sit amet, consectetur adipiscing elit,
                          +markdown

                          Lorem ipsum dolor sit amet, consectetur adipiscing elit,
                          sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

                          -
                          +
                          markdown

                          Lorem ipsum dolor sit amet, consectetur adipiscing elit,
                          +markdown

                          Lorem ipsum dolor sit amet, consectetur adipiscing elit,
                          sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

                          -
                          +
                          markdown

                          Lorem ipsum dolor sit amet, consectetur adipiscing elit,
                          +markdown

                          Lorem ipsum dolor sit amet, consectetur adipiscing elit,
                          sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

                          -
                          +
                          markdown

                          Lorem ipsum dolor sit amet, consectetur adipiscing elit,
                          +markdown

                          Lorem ipsum dolor sit amet, consectetur adipiscing elit,
                          sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

                          -
                          +
                          {
                          +
                          {
                           	fenced: "block",
                           	of: "json",
                           }
                           
                          -
                          ab +
                          ab
                          {
                          +
                          {
                           	fenced: "block",
                           	of: "json",
                           }
                           
                          -
                          ab +
                          ab

                          a line of text and an

                          +

                          a line of text and an

                          {
                           	indented: "block",
                           	of: "json",
                           }
                           
                          -
                          ab +
                          ab

                          a line of text and an

                          +

                          a line of text and an

                          {
                           	indented: "block",
                           	of: "json",
                           }
                           
                          -
                          ab +
                          ab

                          code

                          -
                          ab +

                          code

                          +
                          ab

                          code

                          -
                          ab +

                          code

                          +
                          ab

                          A paragraph is simply one or more consecutive lines of text, separated +

                          A paragraph is simply one or more consecutive lines of text, separated by one or more blank lines. (A blank line is any line that looks like a blank line -- a line containing nothing but spaces or tabs is considered blank.) Normal paragraphs should not be indented with spaces or tabs.

                          -
                          ab +
                          ab

                          A paragraph is simply one or more consecutive lines of text, separated +

                          A paragraph is simply one or more consecutive lines of text, separated by one or more blank lines. (A blank line is any line that looks like a blank line -- a line containing nothing but spaces or tabs is considered blank.) Normal paragraphs should not be indented with spaces or tabs.

                          -
                          ab +
                          ab

                          Here is an example of AppleScript:

                          +

                          Here is an example of AppleScript:

                          tell application "Foo"
                               beep
                           end tell
                           

                          A code block continues until it reaches a line that is not indented (or the end of the article).

                          -
                          ab +
                          ab

                          Here is an example of AppleScript:

                          +

                          Here is an example of AppleScript:

                          tell application "Foo"
                               beep
                           end tell
                           

                          A code block continues until it reaches a line that is not indented (or the end of the article).

                          -
                          ab +
                          ab