Monorepo for Tangled tangled.org

appview/pages/markup: add support for callouts

Signed-off-by: Anirudh Oppiliappan <anirudh@tangled.org>

Changed files
+91 -20
appview
+4 -4
appview/pages/funcmap.go
··· 265 265 return nil 266 266 }, 267 267 "i": func(name string, classes ...string) template.HTML { 268 - data, err := icon(name, classes) 268 + data, err := p.icon(name, classes) 269 269 if err != nil { 270 270 log.Printf("icon %s does not exist", name) 271 - data, _ = icon("airplay", classes) 271 + data, _ = p.icon("airplay", classes) 272 272 } 273 273 return template.HTML(data) 274 274 }, 275 - "cssContentHash": CssContentHash, 275 + "cssContentHash": p.CssContentHash, 276 276 "fileTree": filetree.FileTree, 277 277 "pathEscape": func(s string) string { 278 278 return url.PathEscape(s) ··· 325 325 return fmt.Sprintf("%s/%s/%s?%s", p.avatar.Host, signature, handle, sizeArg) 326 326 } 327 327 328 - func icon(name string, classes []string) (template.HTML, error) { 328 + func (p *Pages) icon(name string, classes []string) (template.HTML, error) { 329 329 iconPath := filepath.Join("static", "icons", name) 330 330 331 331 if filepath.Ext(name) == "" {
+6 -1
appview/pages/markup/markdown.go
··· 5 5 "bytes" 6 6 "fmt" 7 7 "io" 8 + "io/fs" 8 9 "net/url" 9 10 "path" 10 11 "strings" ··· 20 21 "github.com/yuin/goldmark/renderer/html" 21 22 "github.com/yuin/goldmark/text" 22 23 "github.com/yuin/goldmark/util" 24 + callout "gitlab.com/staticnoise/goldmark-callout" 23 25 htmlparse "golang.org/x/net/html" 24 26 25 27 "tangled.org/core/api/tangled" ··· 45 47 IsDev bool 46 48 RendererType RendererType 47 49 Sanitizer Sanitizer 50 + Files fs.FS 48 51 } 49 52 50 53 func (rctx *RenderContext) RenderMarkdown(source string) string { ··· 62 65 extension.WithFootnoteIDPrefix([]byte("footnote")), 63 66 ), 64 67 treeblood.MathML(), 68 + callout.CalloutExtention, 65 69 ), 66 70 goldmark.WithParserOptions( 67 71 parser.WithAutoHeadingID(), ··· 140 144 func visitNode(ctx *RenderContext, node *htmlparse.Node) { 141 145 switch node.Type { 142 146 case htmlparse.ElementNode: 143 - if node.Data == "img" || node.Data == "source" { 147 + switch node.Data { 148 + case "img", "source": 144 149 for i, attr := range node.Attr { 145 150 if attr.Key != "src" { 146 151 continue
+3
appview/pages/markup/sanitizer.go
··· 114 114 policy.AllowNoAttrs().OnElements(mathElements...) 115 115 policy.AllowAttrs(mathAttrs...).OnElements(mathElements...) 116 116 117 + // goldmark-callout 118 + policy.AllowAttrs("data-callout").OnElements("details") 119 + 117 120 return policy 118 121 } 119 122
+4 -3
appview/pages/pages.go
··· 61 61 CamoUrl: config.Camo.Host, 62 62 CamoSecret: config.Camo.SharedSecret, 63 63 Sanitizer: markup.NewSanitizer(), 64 + Files: Files, 64 65 } 65 66 66 67 p := &Pages{ ··· 1475 1476 return http.StripPrefix("/static/", http.FileServer(http.Dir("appview/pages/static"))) 1476 1477 } 1477 1478 1478 - sub, err := fs.Sub(Files, "static") 1479 + sub, err := fs.Sub(p.embedFS, "static") 1479 1480 if err != nil { 1480 1481 p.logger.Error("no static dir found? that's crazy", "err", err) 1481 1482 panic(err) ··· 1498 1499 }) 1499 1500 } 1500 1501 1501 - func CssContentHash() string { 1502 - cssFile, err := Files.Open("static/tw.css") 1502 + func (p *Pages) CssContentHash() string { 1503 + cssFile, err := p.embedFS.Open("static/tw.css") 1503 1504 if err != nil { 1504 1505 slog.Debug("Error opening CSS file", "err", err) 1505 1506 return ""
+1
go.mod
··· 157 157 github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect 158 158 github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect 159 159 github.com/wyatt915/treeblood v0.1.15 // indirect 160 + gitlab.com/staticnoise/goldmark-callout v0.0.0-20240609120641-6366b799e4ab // indirect 160 161 gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect 161 162 gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect 162 163 go.opentelemetry.io/auto/sdk v1.1.0 // indirect
+2
go.sum
··· 442 442 github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= 443 443 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= 444 444 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= 445 + gitlab.com/staticnoise/goldmark-callout v0.0.0-20240609120641-6366b799e4ab h1:gK9tS6QJw5F0SIhYJnGG2P83kuabOdmWBbSmZhJkz2A= 446 + gitlab.com/staticnoise/goldmark-callout v0.0.0-20240609120641-6366b799e4ab/go.mod h1:SPu13/NPe1kMrbGoJldQwqtpNhXsmIuHCfm/aaGjU0c= 445 447 gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA= 446 448 gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8= 447 449 gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q=
+71 -12
input.css
··· 134 134 } 135 135 136 136 .prose hr { 137 - @apply my-2; 137 + @apply my-2; 138 138 } 139 139 140 140 .prose li:has(input) { 141 - @apply list-none; 141 + @apply list-none; 142 142 } 143 143 144 144 .prose ul:has(input) { 145 - @apply pl-2; 145 + @apply pl-2; 146 146 } 147 147 148 148 .prose .heading .anchor { 149 - @apply no-underline mx-2 opacity-0; 149 + @apply no-underline mx-2 opacity-0; 150 150 } 151 151 152 152 .prose .heading:hover .anchor { 153 - @apply opacity-70; 153 + @apply opacity-70; 154 154 } 155 155 156 156 .prose .heading .anchor:hover { 157 - @apply opacity-70; 157 + @apply opacity-70; 158 158 } 159 159 160 160 .prose a.footnote-backref { 161 - @apply no-underline; 161 + @apply no-underline; 162 162 } 163 163 164 164 .prose li { 165 - @apply my-0 py-0; 165 + @apply my-0 py-0; 166 166 } 167 167 168 - .prose ul, .prose ol { 169 - @apply my-1 py-0; 168 + .prose ul, 169 + .prose ol { 170 + @apply my-1 py-0; 170 171 } 171 172 172 173 .prose img { ··· 176 177 } 177 178 178 179 .prose input { 179 - @apply inline-block my-0 mb-1 mx-1; 180 + @apply inline-block my-0 mb-1 mx-1; 180 181 } 181 182 182 183 .prose input[type="checkbox"] { 183 184 @apply disabled:accent-blue-500 checked:accent-blue-500 disabled:checked:accent-blue-500; 184 185 } 186 + 187 + /* Base callout */ 188 + details[data-callout] { 189 + @apply border-l-4 pl-3 py-2 text-gray-800 dark:text-gray-200 my-4; 190 + } 191 + 192 + details[data-callout] > summary { 193 + @apply font-bold cursor-pointer mb-1; 194 + } 195 + 196 + details[data-callout] > .callout-content { 197 + @apply text-sm leading-snug; 198 + } 199 + 200 + /* Note (blue) */ 201 + details[data-callout="note" i] { 202 + @apply border-blue-400 dark:border-blue-500; 203 + } 204 + details[data-callout="note" i] > summary { 205 + @apply text-blue-700 dark:text-blue-400; 206 + } 207 + 208 + /* Important (purple) */ 209 + details[data-callout="important" i] { 210 + @apply border-purple-400 dark:border-purple-500; 211 + } 212 + details[data-callout="important" i] > summary { 213 + @apply text-purple-700 dark:text-purple-400; 214 + } 215 + 216 + /* Warning (yellow) */ 217 + details[data-callout="warning" i] { 218 + @apply border-yellow-400 dark:border-yellow-500; 219 + } 220 + details[data-callout="warning" i] > summary { 221 + @apply text-yellow-700 dark:text-yellow-400; 222 + } 223 + 224 + /* Caution (red) */ 225 + details[data-callout="caution" i] { 226 + @apply border-red-400 dark:border-red-500; 227 + } 228 + details[data-callout="caution" i] > summary { 229 + @apply text-red-700 dark:text-red-400; 230 + } 231 + 232 + /* Tip (green) */ 233 + details[data-callout="tip" i] { 234 + @apply border-green-400 dark:border-green-500; 235 + } 236 + details[data-callout="tip" i] > summary { 237 + @apply text-green-700 dark:text-green-400; 238 + } 239 + 240 + /* Optional: hide the disclosure arrow like GitHub */ 241 + details[data-callout] > summary::-webkit-details-marker { 242 + display: none; 243 + } 185 244 } 186 245 @layer utilities { 187 246 .error { ··· 228 287 } 229 288 /* LineHighlight */ 230 289 .chroma .hl { 231 - @apply bg-amber-400/30 dark:bg-amber-500/20; 290 + @apply bg-amber-400/30 dark:bg-amber-500/20; 232 291 } 233 292 234 293 /* LineNumbersTable */