Skip to content

Commit

Permalink
Add color preview to markdown
Browse files Browse the repository at this point in the history
Signed-off-by: Yarden Shoham <hrsi88@gmail.com>
  • Loading branch information
yardenshoham committed Oct 17, 2022
1 parent 11ac14c commit 80dae5f
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 2 deletions.
36 changes: 36 additions & 0 deletions modules/markup/markdown/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,39 @@ func IsIcon(node ast.Node) bool {
_, ok := node.(*Icon)
return ok
}

// ColorPreview is an inline for a color preview
type ColorPreview struct {
ast.BaseInline
Color []byte
}

// Dump implements Node.Dump.
func (n *ColorPreview) Dump(source []byte, level int) {
m := map[string]string{}
m["Color"] = string(n.Color)
ast.DumpHelper(n, source, level, m, nil)
}

// KindColorPreview is the NodeKind for ColorPreview
var KindColorPreview = ast.NewNodeKind("ColorPreview")

// Kind implements Node.Kind.
func (n *ColorPreview) Kind() ast.NodeKind {
return KindColorPreview
}

// NewColorPreview returns a new Span node.
func NewColorPreview(color []byte) *ColorPreview {
return &ColorPreview{
BaseInline: ast.BaseInline{},
Color: color,
}
}

// IsColorPreview returns true if the given node implements the ColorPreview interface,
// otherwise false.
func IsColorPreview(node ast.Node) bool {
_, ok := node.(*ColorPreview)
return ok
}
24 changes: 24 additions & 0 deletions modules/markup/markdown/goldmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import (

var byteMailto = []byte("mailto:")

var cssColorRegex = regexp.MustCompile(`(?i)(#(?:[0-9a-f]{2}){2,4}$|(#[0-9a-f]{3}$)|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d\.]+%?\))$`)

// ASTTransformer is a default transformer of the goldmark tree.
type ASTTransformer struct{}

Expand Down Expand Up @@ -178,6 +180,11 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
v.SetHardLineBreak(setting.Markdown.EnableHardLineBreakInDocuments)
}
}
case *ast.CodeSpan:
colorContent := n.Text(reader.Source())
if cssColorRegex.Match(colorContent) {
v.Parent().InsertAfter(v.Parent(), v, NewColorPreview(colorContent))
}
}
return ast.WalkContinue, nil
})
Expand Down Expand Up @@ -266,6 +273,7 @@ func (r *HTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(KindDetails, r.renderDetails)
reg.Register(KindSummary, r.renderSummary)
reg.Register(KindIcon, r.renderIcon)
reg.Register(KindColorPreview, r.renderColorPreview)
reg.Register(KindTaskCheckBoxListItem, r.renderTaskCheckBoxListItem)
reg.Register(east.KindTaskCheckBox, r.renderTaskCheckBox)
}
Expand Down Expand Up @@ -356,6 +364,22 @@ func (r *HTMLRenderer) renderIcon(w util.BufWriter, source []byte, node ast.Node
return ast.WalkContinue, nil
}

func (r *HTMLRenderer) renderColorPreview(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
var err error
n := node.(*ColorPreview)
if entering {
_, err = w.WriteString(fmt.Sprintf(`<code class="color-preview"><span class="repo-icon rounded" style="background-color: %v">`, string(n.Color)))
} else {
_, err = w.WriteString("</span></code>")
}

if err != nil {
return ast.WalkStop, err
}

return ast.WalkContinue, nil
}

func (r *HTMLRenderer) renderTaskCheckBoxListItem(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
n := node.(*TaskCheckBoxListItem)
if entering {
Expand Down
8 changes: 6 additions & 2 deletions modules/markup/sanitizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ func createDefaultPolicy() *bluemonday.Policy {
// For JS code copy and Mermaid loading state
policy.AllowAttrs("class").Matching(regexp.MustCompile(`^code-block( is-loading)?$`)).OnElements("pre")

// For color preview
policy.AllowAttrs("class").Matching(regexp.MustCompile(`^repo-icon rounded$`)).OnElements("span")
policy.AllowAttrs("class").Matching(regexp.MustCompile("^color-preview$")).OnElements("code")

// For Chroma markdown plugin
policy.AllowAttrs("class").Matching(regexp.MustCompile(`^(chroma )?language-[\w-]+( display)?( is-loading)?$`)).OnElements("code")

Expand Down Expand Up @@ -88,8 +92,8 @@ func createDefaultPolicy() *bluemonday.Policy {
// Allow 'style' attribute on text elements.
policy.AllowAttrs("style").OnElements("span", "p")

// Allow 'color' property for the style attribute on text elements.
policy.AllowStyles("color").OnElements("span", "p")
// Allow 'color' and 'background-color' properties for the style attribute on text elements.
policy.AllowStyles("color", "background-color").OnElements("span", "p")

// Allow generally safe attributes
generalSafeAttrs := []string{
Expand Down
16 changes: 16 additions & 0 deletions web_src/less/_base.less
Original file line number Diff line number Diff line change
Expand Up @@ -1371,6 +1371,22 @@ a.ui.card:hover,
border-color: var(--color-secondary);
}

.color-preview {
padding-left: 0 !important;
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
span {
height: 7px;
width: 7px;
}
}

code:has(+ .color-preview) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
padding-right: 0.2em;
}

footer {
background-color: var(--color-footer);
border-top: 1px solid var(--color-secondary);
Expand Down

0 comments on commit 80dae5f

Please sign in to comment.