appview/pages/markup: add support for callouts #646

merged
opened by anirudh.fi targeting master from push-pyllqzrprrny
Changed files
+91 -20
appview
+4 -4
appview/pages/funcmap.go
···
return nil
},
"i": func(name string, classes ...string) template.HTML {
-
data, err := icon(name, classes)
+
data, err := p.icon(name, classes)
if err != nil {
log.Printf("icon %s does not exist", name)
-
data, _ = icon("airplay", classes)
+
data, _ = p.icon("airplay", classes)
}
return template.HTML(data)
},
-
"cssContentHash": CssContentHash,
+
"cssContentHash": p.CssContentHash,
"fileTree": filetree.FileTree,
"pathEscape": func(s string) string {
return url.PathEscape(s)
···
return fmt.Sprintf("%s/%s/%s?%s", p.avatar.Host, signature, handle, sizeArg)
}
-
func icon(name string, classes []string) (template.HTML, error) {
+
func (p *Pages) icon(name string, classes []string) (template.HTML, error) {
iconPath := filepath.Join("static", "icons", name)
if filepath.Ext(name) == "" {
+6 -1
appview/pages/markup/markdown.go
···
"bytes"
"fmt"
"io"
+
"io/fs"
"net/url"
"path"
"strings"
···
"github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
+
callout "gitlab.com/staticnoise/goldmark-callout"
htmlparse "golang.org/x/net/html"
"tangled.org/core/api/tangled"
···
IsDev bool
RendererType RendererType
Sanitizer Sanitizer
+
Files fs.FS
}
func (rctx *RenderContext) RenderMarkdown(source string) string {
···
extension.WithFootnoteIDPrefix([]byte("footnote")),
),
treeblood.MathML(),
+
callout.CalloutExtention,
),
goldmark.WithParserOptions(
parser.WithAutoHeadingID(),
···
func visitNode(ctx *RenderContext, node *htmlparse.Node) {
switch node.Type {
case htmlparse.ElementNode:
-
if node.Data == "img" || node.Data == "source" {
+
switch node.Data {
+
case "img", "source":
for i, attr := range node.Attr {
if attr.Key != "src" {
continue
+3
appview/pages/markup/sanitizer.go
···
policy.AllowNoAttrs().OnElements(mathElements...)
policy.AllowAttrs(mathAttrs...).OnElements(mathElements...)
+
// goldmark-callout
+
policy.AllowAttrs("data-callout").OnElements("details")
+
return policy
}
+4 -3
appview/pages/pages.go
···
CamoUrl: config.Camo.Host,
CamoSecret: config.Camo.SharedSecret,
Sanitizer: markup.NewSanitizer(),
+
Files: Files,
}
p := &Pages{
···
return http.StripPrefix("/static/", http.FileServer(http.Dir("appview/pages/static")))
-
sub, err := fs.Sub(Files, "static")
+
sub, err := fs.Sub(p.embedFS, "static")
if err != nil {
p.logger.Error("no static dir found? that's crazy", "err", err)
panic(err)
···
})
-
func CssContentHash() string {
-
cssFile, err := Files.Open("static/tw.css")
+
func (p *Pages) CssContentHash() string {
+
cssFile, err := p.embedFS.Open("static/tw.css")
if err != nil {
slog.Debug("Error opening CSS file", "err", err)
return ""
+1
go.mod
···
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/wyatt915/treeblood v0.1.15 // indirect
+
gitlab.com/staticnoise/goldmark-callout v0.0.0-20240609120641-6366b799e4ab // indirect
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
+2
go.sum
···
github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
+
gitlab.com/staticnoise/goldmark-callout v0.0.0-20240609120641-6366b799e4ab h1:gK9tS6QJw5F0SIhYJnGG2P83kuabOdmWBbSmZhJkz2A=
+
gitlab.com/staticnoise/goldmark-callout v0.0.0-20240609120641-6366b799e4ab/go.mod h1:SPu13/NPe1kMrbGoJldQwqtpNhXsmIuHCfm/aaGjU0c=
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA=
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8=
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q=
+71 -12
input.css
···
}
.prose hr {
-
@apply my-2;
+
@apply my-2;
}
.prose li:has(input) {
-
@apply list-none;
+
@apply list-none;
}
.prose ul:has(input) {
-
@apply pl-2;
+
@apply pl-2;
}
.prose .heading .anchor {
-
@apply no-underline mx-2 opacity-0;
+
@apply no-underline mx-2 opacity-0;
}
.prose .heading:hover .anchor {
-
@apply opacity-70;
+
@apply opacity-70;
}
.prose .heading .anchor:hover {
-
@apply opacity-70;
+
@apply opacity-70;
}
.prose a.footnote-backref {
-
@apply no-underline;
+
@apply no-underline;
}
.prose li {
-
@apply my-0 py-0;
+
@apply my-0 py-0;
}
-
.prose ul, .prose ol {
-
@apply my-1 py-0;
+
.prose ul,
+
.prose ol {
+
@apply my-1 py-0;
}
.prose img {
···
}
.prose input {
-
@apply inline-block my-0 mb-1 mx-1;
+
@apply inline-block my-0 mb-1 mx-1;
}
.prose input[type="checkbox"] {
@apply disabled:accent-blue-500 checked:accent-blue-500 disabled:checked:accent-blue-500;
}
+
+
/* Base callout */
+
details[data-callout] {
+
@apply border-l-4 pl-3 py-2 text-gray-800 dark:text-gray-200 my-4;
+
}
+
+
details[data-callout] > summary {
+
@apply font-bold cursor-pointer mb-1;
+
}
+
+
details[data-callout] > .callout-content {
+
@apply text-sm leading-snug;
+
}
+
+
/* Note (blue) */
+
details[data-callout="note"] {
+
@apply border-blue-400 dark:border-blue-500;
+
}
+
details[data-callout="note"] > summary {
+
@apply text-blue-700 dark:text-blue-400;
+
}
+
+
/* Important (purple) */
+
details[data-callout="important"] {
+
@apply border-purple-400 dark:border-purple-500;
+
}
+
details[data-callout="important"] > summary {
+
@apply text-purple-700 dark:text-purple-400;
+
}
+
+
/* Warning (yellow) */
+
details[data-callout="warning"] {
+
@apply border-yellow-400 dark:border-yellow-500;
+
}
+
details[data-callout="warning"] > summary {
+
@apply text-yellow-700 dark:text-yellow-400;
+
}
+
+
/* Caution (red) */
+
details[data-callout="caution"] {
+
@apply border-red-400 dark:border-red-500;
+
}
+
details[data-callout="caution"] > summary {
+
@apply text-red-700 dark:text-red-400;
+
}
+
+
/* Tip (green) */
+
details[data-callout="tip"] {
+
@apply border-green-400 dark:border-green-500;
+
}
+
details[data-callout="tip"] > summary {
+
@apply text-green-700 dark:text-green-400;
+
}
+
+
/* Optional: hide the disclosure arrow like GitHub */
+
details[data-callout] > summary::-webkit-details-marker {
+
display: none;
+
}
}
@layer utilities {
.error {
···
}
/* LineHighlight */
.chroma .hl {
-
@apply bg-amber-400/30 dark:bg-amber-500/20;
+
@apply bg-amber-400/30 dark:bg-amber-500/20;
}
/* LineNumbersTable */