Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add attention blocks within quote blocks for Note and Warning #21711

Merged
merged 11 commits into from
Nov 9, 2022
34 changes: 34 additions & 0 deletions modules/markup/markdown/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,37 @@ func IsColorPreview(node ast.Node) bool {
_, ok := node.(*ColorPreview)
return ok
}

const (
AttentionNote string = "note"
AttentionWarning string = "warning"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. It might be a good idea to explicitly define a subtype of string for the available highlight types.
  2. sphinx recognises the following things:

Admonitions: attention, caution, danger, error, hint, important, note, tip, warning and the generic admonition. (Most themes style only “note” and “warning” specially.)

We could think about also supporting the rest, but maybe that's also overkill for this PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's overkill but this PR will make it easy to have it in the future by laying the groundwork

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a native English speaker, is admonition a better name for this feature than attention?

)

// Attention is an inline for a color preview
type Attention struct {
ast.BaseInline
AttentionType string
}

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

// KindAttention is the NodeKind for Attention
var KindAttention = ast.NewNodeKind("Attention")

// Kind implements Node.Kind.
func (n *Attention) Kind() ast.NodeKind {
return KindAttention
}

// NewAttention returns a new Attention node.
func NewAttention(attentionType string) *Attention {
return &Attention{
BaseInline: ast.BaseInline{},
AttentionType: attentionType,
}
}
36 changes: 36 additions & 0 deletions modules/markup/markdown/goldmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import (

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

const hasThisBlockquoteBeenAttentionMarked = "has-this-blockquote-been-attention-marked"

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

Expand Down Expand Up @@ -184,6 +186,18 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
if css.ColorHandler(strings.ToLower(string(colorContent))) {
v.AppendChild(v, NewColorPreview(colorContent))
}
case *ast.Emphasis:
grandparent := n.Parent().Parent()
yardenshoham marked this conversation as resolved.
Show resolved Hide resolved
_, isInBlockquote := grandparent.(*ast.Blockquote)
_, blockquoteAlreadyAttentionMarked := grandparent.AttributeString(hasThisBlockquoteBeenAttentionMarked)
if !blockquoteAlreadyAttentionMarked && isInBlockquote {
yardenshoham marked this conversation as resolved.
Show resolved Hide resolved
fullText := strings.ToLower(string(n.Text(reader.Source())))
if fullText == AttentionNote || fullText == AttentionWarning {
v.SetAttributeString("class", []byte("attention-"+fullText))
v.Parent().InsertBefore(v.Parent(), v, NewAttention(fullText))
grandparent.SetAttributeString(hasThisBlockquoteBeenAttentionMarked, []byte("yes"))
}
}
}
return ast.WalkContinue, nil
})
Expand Down Expand Up @@ -273,6 +287,7 @@ func (r *HTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(KindSummary, r.renderSummary)
reg.Register(KindIcon, r.renderIcon)
reg.Register(ast.KindCodeSpan, r.renderCodeSpan)
reg.Register(KindAttention, r.renderAttention)
reg.Register(KindTaskCheckBoxListItem, r.renderTaskCheckBoxListItem)
reg.Register(east.KindTaskCheckBox, r.renderTaskCheckBox)
}
Expand Down Expand Up @@ -309,6 +324,27 @@ func (r *HTMLRenderer) renderCodeSpan(w util.BufWriter, source []byte, n ast.Nod
return ast.WalkContinue, nil
}

func (r *HTMLRenderer) renderAttention(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
yardenshoham marked this conversation as resolved.
Show resolved Hide resolved
if entering {
_, _ = w.WriteString(`<span class="attention-`)
n := node.(*Attention)
_, _ = w.WriteString(n.AttentionType)
_, _ = w.WriteString(`">`)

// TODO: Use code.gitea.io/gitea/modules/templates SVG function instead
// @yardenshoham didn't do it because when he tried to import code.gitea.io/gitea/modules/templates he got a cyclical import error
switch n.AttentionType {
case AttentionNote:
_, _ = w.WriteString(`<svg viewBox="0 0 16 16" class="svg octicon-info" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M8 1.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13zM0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm6.5-.25A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75zM8 6a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"></path></svg>`)
case AttentionWarning:
_, _ = w.WriteString(`<svg viewBox="0 0 16 16" class="svg octicon-alert" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M8.22 1.754a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368L8.22 1.754zm-1.763-.707c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575L6.457 1.047zM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-.25-5.25a.75.75 0 0 0-1.5 0v2.5a.75.75 0 0 0 1.5 0v-2.5z"></path></svg>`)
}
} else {
_, _ = w.WriteString("</span>\n")
}
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)

Expand Down
6 changes: 6 additions & 0 deletions modules/markup/sanitizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ func createDefaultPolicy() *bluemonday.Policy {
// For color preview
policy.AllowAttrs("class").Matching(regexp.MustCompile(`^color-preview$`)).OnElements("span")

// For attention
policy.AllowAttrs("class").Matching(regexp.MustCompile(`^attention-\w+$`)).OnElements("span", "strong")
policy.AllowAttrs("class").Matching(regexp.MustCompile(`^svg octicon-\w+$`)).OnElements("svg")
policy.AllowAttrs("viewBox", "width", "height", "aria-hidden").OnElements("svg")
policy.AllowAttrs("fill-rule", "d").OnElements("path")
yardenshoham marked this conversation as resolved.
Show resolved Hide resolved

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

Expand Down
14 changes: 14 additions & 0 deletions web_src/less/_base.less
Original file line number Diff line number Diff line change
Expand Up @@ -1732,6 +1732,20 @@ a.ui.card:hover,
border-radius: .15em;
}

.attention() {
font-weight: unset;
}

.attention-note {
.attention;
color: var(--color-info-text);
}

.attention-warning {
.attention;
color: var(--color-warning-text);
yardenshoham marked this conversation as resolved.
Show resolved Hide resolved
}

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