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">aa bb ll mm oo cc ii kk dd hh jj ff 11 22 33 44 55 66 77 88
+aa bb ll mm oo cc ii kk dd hh jj ff 11 22 33 44 55 66 77 88
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">aa bb ll mm oo cc ii kk dd hh jj ff 11 22 33 44 55 66 77 88
+aa bb ll mm oo cc ii kk dd hh jj ff 11 22 33 44 55 66 77 88
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:
- a b
+ a b
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:
- a b
+ a b
Note: This document is itself written using Markdown; you
+a b
+
a b
Note: This document is itself written using Markdown; you
+a b
+
a b
mixed together sugar solution we get
+mixed together sugar solution we get
mixed together sugar solution we get
+mixed together sugar solution 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.
- a b
+
a b
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.
- a b
+
a b
Markdown: Syntax
-a b
+
Markdown: Syntax
+a b
Markdown: Syntax
-a b
+
Markdown: Syntax
+a b
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.
-
x y
+ x y
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.
-
x y
+ x y
container 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 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",
}
-
a b
+ a b
{
+{
fenced: "block",
of: "json",
}
-
a b
+ a b
a line of text and an
+
a line of text and an
{
indented: "block",
of: "json",
}
-
a b
+ a b
a line of text and an
+
a line of text and an
{
indented: "block",
of: "json",
}
-
a b
+ a b
a b
+a b
a b
+a b
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.
-
a b
+
a b
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.
-
a b
+
a b
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).
-
a b
+ a b
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).
-
a b
+ a b