Signed-off-by: Anirudh Oppiliappan anirudh@tangled.org
+4
-4
appview/pages/funcmap.go
+4
-4
appview/pages/funcmap.go
···
265
return nil
266
},
267
"i": func(name string, classes ...string) template.HTML {
268
-
data, err := icon(name, classes)
269
if err != nil {
270
log.Printf("icon %s does not exist", name)
271
-
data, _ = icon("airplay", classes)
272
}
273
return template.HTML(data)
274
},
275
-
"cssContentHash": CssContentHash,
276
"fileTree": filetree.FileTree,
277
"pathEscape": func(s string) string {
278
return url.PathEscape(s)
···
325
return fmt.Sprintf("%s/%s/%s?%s", p.avatar.Host, signature, handle, sizeArg)
326
}
327
328
-
func icon(name string, classes []string) (template.HTML, error) {
329
iconPath := filepath.Join("static", "icons", name)
330
331
if filepath.Ext(name) == "" {
···
265
return nil
266
},
267
"i": func(name string, classes ...string) template.HTML {
268
+
data, err := p.icon(name, classes)
269
if err != nil {
270
log.Printf("icon %s does not exist", name)
271
+
data, _ = p.icon("airplay", classes)
272
}
273
return template.HTML(data)
274
},
275
+
"cssContentHash": p.CssContentHash,
276
"fileTree": filetree.FileTree,
277
"pathEscape": func(s string) string {
278
return url.PathEscape(s)
···
325
return fmt.Sprintf("%s/%s/%s?%s", p.avatar.Host, signature, handle, sizeArg)
326
}
327
328
+
func (p *Pages) icon(name string, classes []string) (template.HTML, error) {
329
iconPath := filepath.Join("static", "icons", name)
330
331
if filepath.Ext(name) == "" {
+6
-1
appview/pages/markup/markdown.go
+6
-1
appview/pages/markup/markdown.go
···
5
"bytes"
6
"fmt"
7
"io"
8
"net/url"
9
"path"
10
"strings"
···
20
"github.com/yuin/goldmark/renderer/html"
21
"github.com/yuin/goldmark/text"
22
"github.com/yuin/goldmark/util"
23
htmlparse "golang.org/x/net/html"
24
25
"tangled.org/core/api/tangled"
···
45
IsDev bool
46
RendererType RendererType
47
Sanitizer Sanitizer
48
}
49
50
func (rctx *RenderContext) RenderMarkdown(source string) string {
···
62
extension.WithFootnoteIDPrefix([]byte("footnote")),
63
),
64
treeblood.MathML(),
65
),
66
goldmark.WithParserOptions(
67
parser.WithAutoHeadingID(),
···
140
func visitNode(ctx *RenderContext, node *htmlparse.Node) {
141
switch node.Type {
142
case htmlparse.ElementNode:
143
-
if node.Data == "img" || node.Data == "source" {
144
for i, attr := range node.Attr {
145
if attr.Key != "src" {
146
continue
···
5
"bytes"
6
"fmt"
7
"io"
8
+
"io/fs"
9
"net/url"
10
"path"
11
"strings"
···
21
"github.com/yuin/goldmark/renderer/html"
22
"github.com/yuin/goldmark/text"
23
"github.com/yuin/goldmark/util"
24
+
callout "gitlab.com/staticnoise/goldmark-callout"
25
htmlparse "golang.org/x/net/html"
26
27
"tangled.org/core/api/tangled"
···
47
IsDev bool
48
RendererType RendererType
49
Sanitizer Sanitizer
50
+
Files fs.FS
51
}
52
53
func (rctx *RenderContext) RenderMarkdown(source string) string {
···
65
extension.WithFootnoteIDPrefix([]byte("footnote")),
66
),
67
treeblood.MathML(),
68
+
callout.CalloutExtention,
69
),
70
goldmark.WithParserOptions(
71
parser.WithAutoHeadingID(),
···
144
func visitNode(ctx *RenderContext, node *htmlparse.Node) {
145
switch node.Type {
146
case htmlparse.ElementNode:
147
+
switch node.Data {
148
+
case "img", "source":
149
for i, attr := range node.Attr {
150
if attr.Key != "src" {
151
continue
+3
appview/pages/markup/sanitizer.go
+3
appview/pages/markup/sanitizer.go
+4
-3
appview/pages/pages.go
+4
-3
appview/pages/pages.go
···
61
CamoUrl: config.Camo.Host,
62
CamoSecret: config.Camo.SharedSecret,
63
Sanitizer: markup.NewSanitizer(),
64
}
65
66
p := &Pages{
···
1474
return http.StripPrefix("/static/", http.FileServer(http.Dir("appview/pages/static")))
1475
}
1476
1477
-
sub, err := fs.Sub(Files, "static")
1478
if err != nil {
1479
p.logger.Error("no static dir found? that's crazy", "err", err)
1480
panic(err)
···
1497
})
1498
}
1499
1500
-
func CssContentHash() string {
1501
-
cssFile, err := Files.Open("static/tw.css")
1502
if err != nil {
1503
slog.Debug("Error opening CSS file", "err", err)
1504
return ""
···
61
CamoUrl: config.Camo.Host,
62
CamoSecret: config.Camo.SharedSecret,
63
Sanitizer: markup.NewSanitizer(),
64
+
Files: Files,
65
}
66
67
p := &Pages{
···
1475
return http.StripPrefix("/static/", http.FileServer(http.Dir("appview/pages/static")))
1476
}
1477
1478
+
sub, err := fs.Sub(p.embedFS, "static")
1479
if err != nil {
1480
p.logger.Error("no static dir found? that's crazy", "err", err)
1481
panic(err)
···
1498
})
1499
}
1500
1501
+
func (p *Pages) CssContentHash() string {
1502
+
cssFile, err := p.embedFS.Open("static/tw.css")
1503
if err != nil {
1504
slog.Debug("Error opening CSS file", "err", err)
1505
return ""
+1
go.mod
+1
go.mod
···
157
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
158
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
159
github.com/wyatt915/treeblood v0.1.15 // indirect
160
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect
161
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
162
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
···
157
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
158
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
159
github.com/wyatt915/treeblood v0.1.15 // indirect
160
+
gitlab.com/staticnoise/goldmark-callout v0.0.0-20240609120641-6366b799e4ab // indirect
161
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect
162
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
163
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
+2
go.sum
+2
go.sum
···
440
github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
441
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
442
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
443
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA=
444
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8=
445
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q=
···
440
github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
441
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
442
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I=
443
+
gitlab.com/staticnoise/goldmark-callout v0.0.0-20240609120641-6366b799e4ab h1:gK9tS6QJw5F0SIhYJnGG2P83kuabOdmWBbSmZhJkz2A=
444
+
gitlab.com/staticnoise/goldmark-callout v0.0.0-20240609120641-6366b799e4ab/go.mod h1:SPu13/NPe1kMrbGoJldQwqtpNhXsmIuHCfm/aaGjU0c=
445
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA=
446
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8=
447
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q=
+71
-12
input.css
+71
-12
input.css
···
134
}
135
136
.prose hr {
137
-
@apply my-2;
138
}
139
140
.prose li:has(input) {
141
-
@apply list-none;
142
}
143
144
.prose ul:has(input) {
145
-
@apply pl-2;
146
}
147
148
.prose .heading .anchor {
149
-
@apply no-underline mx-2 opacity-0;
150
}
151
152
.prose .heading:hover .anchor {
153
-
@apply opacity-70;
154
}
155
156
.prose .heading .anchor:hover {
157
-
@apply opacity-70;
158
}
159
160
.prose a.footnote-backref {
161
-
@apply no-underline;
162
}
163
164
.prose li {
165
-
@apply my-0 py-0;
166
}
167
168
-
.prose ul, .prose ol {
169
-
@apply my-1 py-0;
170
}
171
172
.prose img {
···
176
}
177
178
.prose input {
179
-
@apply inline-block my-0 mb-1 mx-1;
180
}
181
182
.prose input[type="checkbox"] {
183
@apply disabled:accent-blue-500 checked:accent-blue-500 disabled:checked:accent-blue-500;
184
}
185
}
186
@layer utilities {
187
.error {
···
228
}
229
/* LineHighlight */
230
.chroma .hl {
231
-
@apply bg-amber-400/30 dark:bg-amber-500/20;
232
}
233
234
/* LineNumbersTable */
···
134
}
135
136
.prose hr {
137
+
@apply my-2;
138
}
139
140
.prose li:has(input) {
141
+
@apply list-none;
142
}
143
144
.prose ul:has(input) {
145
+
@apply pl-2;
146
}
147
148
.prose .heading .anchor {
149
+
@apply no-underline mx-2 opacity-0;
150
}
151
152
.prose .heading:hover .anchor {
153
+
@apply opacity-70;
154
}
155
156
.prose .heading .anchor:hover {
157
+
@apply opacity-70;
158
}
159
160
.prose a.footnote-backref {
161
+
@apply no-underline;
162
}
163
164
.prose li {
165
+
@apply my-0 py-0;
166
}
167
168
+
.prose ul,
169
+
.prose ol {
170
+
@apply my-1 py-0;
171
}
172
173
.prose img {
···
177
}
178
179
.prose input {
180
+
@apply inline-block my-0 mb-1 mx-1;
181
}
182
183
.prose input[type="checkbox"] {
184
@apply disabled:accent-blue-500 checked:accent-blue-500 disabled:checked:accent-blue-500;
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
+
}
244
}
245
@layer utilities {
246
.error {
···
287
}
288
/* LineHighlight */
289
.chroma .hl {
290
+
@apply bg-amber-400/30 dark:bg-amber-500/20;
291
}
292
293
/* LineNumbersTable */