Signed-off-by: oppiliappan me@oppi.li
+39
-1
appview/pages/markup/markdown.go
+39
-1
appview/pages/markup/markdown.go
···
177
switch a.rctx.RendererType {
178
case RendererTypeRepoMarkdown:
179
switch n := n.(type) {
180
case *ast.Link:
181
a.rctx.relativeLinkTransformer(n)
182
case *ast.Image:
···
185
}
186
case RendererTypeDefault:
187
switch n := n.(type) {
188
case *ast.Image:
189
a.rctx.imageFromKnotAstTransformer(n)
190
a.rctx.camoImageLinkAstTransformer(n)
···
199
200
dst := string(link.Destination)
201
202
-
if isAbsoluteUrl(dst) {
203
return
204
}
205
···
240
img.Destination = []byte(rctx.imageFromKnotTransformer(dst))
241
}
242
243
// actualPath decides when to join the file path with the
244
// current repository directory (essentially only when the link
245
// destination is relative. if it's absolute then we assume the
···
259
}
260
return parsed.IsAbs()
261
}
···
177
switch a.rctx.RendererType {
178
case RendererTypeRepoMarkdown:
179
switch n := n.(type) {
180
+
case *ast.Heading:
181
+
a.rctx.anchorHeadingTransformer(n)
182
case *ast.Link:
183
a.rctx.relativeLinkTransformer(n)
184
case *ast.Image:
···
187
}
188
case RendererTypeDefault:
189
switch n := n.(type) {
190
+
case *ast.Heading:
191
+
a.rctx.anchorHeadingTransformer(n)
192
case *ast.Image:
193
a.rctx.imageFromKnotAstTransformer(n)
194
a.rctx.camoImageLinkAstTransformer(n)
···
203
204
dst := string(link.Destination)
205
206
+
if isAbsoluteUrl(dst) || isFragment(dst) || isMail(dst) {
207
return
208
}
209
···
244
img.Destination = []byte(rctx.imageFromKnotTransformer(dst))
245
}
246
247
+
func (rctx *RenderContext) anchorHeadingTransformer(h *ast.Heading) {
248
+
idGeneric, exists := h.AttributeString("id")
249
+
if !exists {
250
+
return // no id, nothing to do
251
+
}
252
+
id, ok := idGeneric.([]byte)
253
+
if !ok {
254
+
return
255
+
}
256
+
257
+
// create anchor link
258
+
anchor := ast.NewLink()
259
+
anchor.Destination = fmt.Appendf(nil, "#%s", string(id))
260
+
anchor.SetAttribute([]byte("class"), []byte("anchor"))
261
+
262
+
// create icon text
263
+
iconText := ast.NewString([]byte("#"))
264
+
anchor.AppendChild(anchor, iconText)
265
+
266
+
// set class on heading
267
+
h.SetAttribute([]byte("class"), []byte("heading"))
268
+
269
+
// append anchor to heading
270
+
h.AppendChild(h, anchor)
271
+
}
272
+
273
// actualPath decides when to join the file path with the
274
// current repository directory (essentially only when the link
275
// destination is relative. if it's absolute then we assume the
···
289
}
290
return parsed.IsAbs()
291
}
292
+
293
+
func isFragment(link string) bool {
294
+
return strings.HasPrefix(link, "#")
295
+
}
296
+
297
+
func isMail(link string) bool {
298
+
return strings.HasPrefix(link, "mailto:")
299
+
}
+1
appview/pages/markup/sanitizer.go
+1
appview/pages/markup/sanitizer.go
···
65
// for code blocks
66
policy.AllowAttrs("class").Matching(regexp.MustCompile(`chroma`)).OnElements("pre")
67
policy.AllowAttrs("class").Matching(regexp.MustCompile(`anchor|footnote-ref|footnote-backref`)).OnElements("a")
68
policy.AllowAttrs("class").Matching(regexp.MustCompile(strings.Join(slices.Collect(maps.Values(chroma.StandardTypes)), "|"))).OnElements("span")
69
70
// centering content
···
65
// for code blocks
66
policy.AllowAttrs("class").Matching(regexp.MustCompile(`chroma`)).OnElements("pre")
67
policy.AllowAttrs("class").Matching(regexp.MustCompile(`anchor|footnote-ref|footnote-backref`)).OnElements("a")
68
+
policy.AllowAttrs("class").Matching(regexp.MustCompile(`heading`)).OnElements("h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8")
69
policy.AllowAttrs("class").Matching(regexp.MustCompile(strings.Join(slices.Collect(maps.Values(chroma.StandardTypes)), "|"))).OnElements("span")
70
71
// centering content
+23
-1
input.css
+23
-1
input.css
···
134
disabled:before:bg-green-400 dark:disabled:before:bg-green-600;
135
}
136
137
+
.prose hr {
138
+
@apply my-2;
139
+
}
140
+
141
.prose li:has(input) {
142
+
@apply list-none;
143
+
}
144
+
145
+
.prose ul:has(input) {
146
+
@apply pl-2;
147
+
}
148
+
149
+
.prose .heading .anchor {
150
+
@apply no-underline mx-2 opacity-0;
151
+
}
152
+
153
+
.prose .heading:hover .anchor {
154
+
@apply opacity-70;
155
+
}
156
+
157
+
.prose .heading .anchor:hover {
158
+
@apply opacity-70;
159
+
}
160
+
161
.prose a.footnote-backref {
162
@apply no-underline;
163
}