Mirror of @tangled.org/core. Running on a Raspberry Pi Zero 2 (Please be gentle).
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

appview/pages/markup: insert anchor link in headings

Signed-off-by: oppiliappan <me@oppi.li>

authored by

oppiliappan and committed by
Tangled
bb4ac7ec 82f4ca08

+63 -2
+39 -1
appview/pages/markup/markdown.go
··· 177 177 switch a.rctx.RendererType { 178 178 case RendererTypeRepoMarkdown: 179 179 switch n := n.(type) { 180 + case *ast.Heading: 181 + a.rctx.anchorHeadingTransformer(n) 180 182 case *ast.Link: 181 183 a.rctx.relativeLinkTransformer(n) 182 184 case *ast.Image: ··· 187 185 } 188 186 case RendererTypeDefault: 189 187 switch n := n.(type) { 188 + case *ast.Heading: 189 + a.rctx.anchorHeadingTransformer(n) 190 190 case *ast.Image: 191 191 a.rctx.imageFromKnotAstTransformer(n) 192 192 a.rctx.camoImageLinkAstTransformer(n) ··· 203 199 204 200 dst := string(link.Destination) 205 201 206 - if isAbsoluteUrl(dst) { 202 + if isAbsoluteUrl(dst) || isFragment(dst) || isMail(dst) { 207 203 return 208 204 } 209 205 ··· 244 240 img.Destination = []byte(rctx.imageFromKnotTransformer(dst)) 245 241 } 246 242 243 + func (rctx *RenderContext) anchorHeadingTransformer(h *ast.Heading) { 244 + idGeneric, exists := h.AttributeString("id") 245 + if !exists { 246 + return // no id, nothing to do 247 + } 248 + id, ok := idGeneric.([]byte) 249 + if !ok { 250 + return 251 + } 252 + 253 + // create anchor link 254 + anchor := ast.NewLink() 255 + anchor.Destination = fmt.Appendf(nil, "#%s", string(id)) 256 + anchor.SetAttribute([]byte("class"), []byte("anchor")) 257 + 258 + // create icon text 259 + iconText := ast.NewString([]byte("#")) 260 + anchor.AppendChild(anchor, iconText) 261 + 262 + // set class on heading 263 + h.SetAttribute([]byte("class"), []byte("heading")) 264 + 265 + // append anchor to heading 266 + h.AppendChild(h, anchor) 267 + } 268 + 247 269 // actualPath decides when to join the file path with the 248 270 // current repository directory (essentially only when the link 249 271 // destination is relative. if it's absolute then we assume the ··· 288 258 return false 289 259 } 290 260 return parsed.IsAbs() 261 + } 262 + 263 + func isFragment(link string) bool { 264 + return strings.HasPrefix(link, "#") 265 + } 266 + 267 + func isMail(link string) bool { 268 + return strings.HasPrefix(link, "mailto:") 291 269 }
+1
appview/pages/markup/sanitizer.go
··· 65 65 // for code blocks 66 66 policy.AllowAttrs("class").Matching(regexp.MustCompile(`chroma`)).OnElements("pre") 67 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") 68 69 policy.AllowAttrs("class").Matching(regexp.MustCompile(strings.Join(slices.Collect(maps.Values(chroma.StandardTypes)), "|"))).OnElements("span") 69 70 70 71 // centering content
+23 -1
input.css
··· 134 134 disabled:before:bg-green-400 dark:disabled:before:bg-green-600; 135 135 } 136 136 137 + .prose hr { 138 + @apply my-2; 139 + } 140 + 137 141 .prose li:has(input) { 138 - list-style: none; 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 + 139 161 .prose a.footnote-backref { 140 162 @apply no-underline; 141 163 }