Signed-off-by: Anirudh Oppiliappan anirudh@tangled.org
+4
-4
appview/pages/funcmap.go
+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
+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
+3
appview/pages/markup/sanitizer.go
+4
-3
appview/pages/pages.go
+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{
···
1474
1475
return http.StripPrefix("/static/", http.FileServer(http.Dir("appview/pages/static")))
1475
1476
}
1476
1477
1477
-
sub, err := fs.Sub(Files, "static")
1478
+
sub, err := fs.Sub(p.embedFS, "static")
1478
1479
if err != nil {
1479
1480
p.logger.Error("no static dir found? that's crazy", "err", err)
1480
1481
panic(err)
···
1497
1498
})
1498
1499
}
1499
1500
1500
-
func CssContentHash() string {
1501
-
cssFile, err := Files.Open("static/tw.css")
1501
+
func (p *Pages) CssContentHash() string {
1502
+
cssFile, err := p.embedFS.Open("static/tw.css")
1502
1503
if err != nil {
1503
1504
slog.Debug("Error opening CSS file", "err", err)
1504
1505
return ""
+1
go.mod
+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
+2
go.sum
···
440
440
github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
441
441
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ=
442
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=
443
445
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA=
444
446
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8=
445
447
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q=
+71
-12
input.css
+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 */