Add color previews in markdown (#21474)

* Resolves #3047

Every time a color code will be in \`backticks`, a cute little color
preview will pop up


[Inspiration](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#supported-color-models)

#### Before

![image](https://user-images.githubusercontent.com/20454870/196631524-298afbbf-d2c8-4018-92a5-0393a693d850.png)

#### After

![image](https://user-images.githubusercontent.com/20454870/196631397-36c561e4-08f5-465a-a36e-76084e30b08a.png)

Signed-off-by: Yarden Shoham <hrsi88@gmail.com>
Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
Yarden Shoham 2022-10-21 15:00:53 +03:00 committed by GitHub
parent 16cbd5b59c
commit e828564445
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 143 additions and 2 deletions

View file

@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/setting"
giteautil "code.gitea.io/gitea/modules/util"
"github.com/microcosm-cc/bluemonday/css"
"github.com/yuin/goldmark/ast"
east "github.com/yuin/goldmark/extension/ast"
"github.com/yuin/goldmark/parser"
@ -178,6 +179,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 css.ColorHandler(strings.ToLower(string(colorContent))) {
v.AppendChild(v, NewColorPreview(colorContent))
}
}
return ast.WalkContinue, nil
})
@ -266,10 +272,43 @@ func (r *HTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(KindDetails, r.renderDetails)
reg.Register(KindSummary, r.renderSummary)
reg.Register(KindIcon, r.renderIcon)
reg.Register(ast.KindCodeSpan, r.renderCodeSpan)
reg.Register(KindTaskCheckBoxListItem, r.renderTaskCheckBoxListItem)
reg.Register(east.KindTaskCheckBox, r.renderTaskCheckBox)
}
// renderCodeSpan renders CodeSpan elements (like goldmark upstream does) but also renders ColorPreview elements.
// See #21474 for reference
func (r *HTMLRenderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
if entering {
if n.Attributes() != nil {
_, _ = w.WriteString("<code")
html.RenderAttributes(w, n, html.CodeAttributeFilter)
_ = w.WriteByte('>')
} else {
_, _ = w.WriteString("<code>")
}
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
switch v := c.(type) {
case *ast.Text:
segment := v.Segment
value := segment.Value(source)
if bytes.HasSuffix(value, []byte("\n")) {
r.Writer.RawWrite(w, value[:len(value)-1])
r.Writer.RawWrite(w, []byte(" "))
} else {
r.Writer.RawWrite(w, value)
}
case *ColorPreview:
_, _ = w.WriteString(fmt.Sprintf(`<span class="color-preview" style="background-color: %v"></span>`, string(v.Color)))
}
}
return ast.WalkSkipChildren, nil
}
_, _ = w.WriteString("</code>")
return ast.WalkContinue, nil
}
func (r *HTMLRenderer) renderDocument(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
n := node.(*ast.Document)