feat: page content
This commit is contained in:
@@ -10,6 +10,7 @@ type PageHeader struct {
|
||||
UID string
|
||||
Title string
|
||||
CoverImageUID string
|
||||
md []byte // markdown of the page //markdown of the page
|
||||
}
|
||||
|
||||
type Page struct {
|
||||
@@ -41,51 +42,18 @@ func (s *Service) GetPages(ctx context.Context) (pages []PageHeader, err error)
|
||||
|
||||
func (s *Service) GetPage(ctx context.Context, uid string) (page Page, err error) {
|
||||
p, err := s.getPageHeaders(ctx, uid)
|
||||
slog.Debug("got page", "page", p, "err", err)
|
||||
content := `
|
||||
<h1>LOL</h1>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis ligula vel nisl pellentesque aliquet. Maecenas eu congue tortor. Nunc mattis ligula vel augue viverra cursus. Suspendisse potenti. Vivamus in risus vitae mi molestie feugiat. Cras sapien tortor, elementum ut tempus vel, commodo at dui. In hac habitasse platea dictumst. Integer nec ullamcorper purus, tincidunt elementum felis. Duis hendrerit tempor vestibulum. Nunc ut finibus tellus. Donec eu lacus sit amet sem suscipit imperdiet. Quisque cursus vulputate sodales. In sit amet nisl a est lacinia sagittis. </p>
|
||||
<img fetchpriority="low" loading="lazy" src="https://picsum.photos/500/1000">
|
||||
<h2>LOL</h2>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis ligula vel nisl pellentesque aliquet. Maecenas eu congue tortor. Nunc mattis ligula vel augue viverra cursus. Suspendisse potenti. Vivamus in risus vitae mi molestie feugiat. Cras sapien tortor, elementum ut tempus vel, commodo at dui. In hac habitasse platea dictumst. Integer nec ullamcorper purus, tincidunt elementum felis. Duis hendrerit tempor vestibulum. Nunc ut finibus tellus. Donec eu lacus sit amet sem suscipit imperdiet. Quisque cursus vulputate sodales. In sit amet nisl a est lacinia sagittis. </p>
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
<img fetchpriority="low" loading="lazy" src="https://picsum.photos/600/500">
|
||||
html, err := s.getHTML(ctx, p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis ligula vel nisl pellentesque aliquet. Maecenas eu congue tortor. Nunc mattis ligula vel augue viverra cursus. Suspendisse potenti. Vivamus in risus vitae mi molestie feugiat. Cras sapien tortor, elementum ut tempus vel, commodo at dui. In hac habitasse platea dictumst. Integer nec ullamcorper purus, tincidunt elementum felis. Duis hendrerit tempor vestibulum. Nunc ut finibus tellus. Donec eu lacus sit amet sem suscipit imperdiet. Quisque cursus vulputate sodales. In sit amet nisl a est lacinia sagittis. </p>
|
||||
|
||||
<h3>LOL</h3>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis ligula vel nisl pellentesque aliquet. Maecenas eu congue tortor. Nunc mattis ligula vel augue viverra cursus. Suspendisse potenti. Vivamus in risus vitae mi molestie feugiat. Cras sapien tortor, elementum ut tempus vel, commodo at dui. In hac habitasse platea dictumst. Integer nec ullamcorper purus, tincidunt elementum felis. Duis hendrerit tempor vestibulum. Nunc ut finibus tellus. Donec eu lacus sit amet sem suscipit imperdiet. Quisque cursus vulputate sodales. In sit amet nisl a est lacinia sagittis. </p>
|
||||
<h2>LOL</h2>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis ligula vel nisl pellentesque aliquet. Maecenas eu congue tortor. Nunc mattis ligula vel augue viverra cursus. Suspendisse potenti. Vivamus in risus vitae mi molestie feugiat. Cras sapien tortor, elementum ut tempus vel, commodo at dui. In hac habitasse platea dictumst. Integer nec ullamcorper purus, tincidunt elementum felis. Duis hendrerit tempor vestibulum. Nunc ut finibus tellus. Donec eu lacus sit amet sem suscipit imperdiet. Quisque cursus vulputate sodales. In sit amet nisl a est lacinia sagittis. </p>
|
||||
|
||||
<img fetchpriority="low" loading="lazy" src="https://picsum.photos/601/500">
|
||||
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis ligula vel nisl pellentesque aliquet. Maecenas eu congue tortor. Nunc mattis ligula vel augue viverra cursus. Suspendisse potenti. Vivamus in risus vitae mi molestie feugiat. Cras sapien tortor, elementum ut tempus vel, commodo at dui. In hac habitasse platea dictumst. Integer nec ullamcorper purus, tincidunt elementum felis. Duis hendrerit tempor vestibulum. Nunc ut finibus tellus. Donec eu lacus sit amet sem suscipit imperdiet. Quisque cursus vulputate sodales. In sit amet nisl a est lacinia sagittis. </p>
|
||||
|
||||
<h2>LOL</h2>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis ligula vel nisl pellentesque aliquet. Maecenas eu congue tortor. Nunc mattis ligula vel augue viverra cursus. Suspendisse potenti. Vivamus in risus vitae mi molestie feugiat. Cras sapien tortor, elementum ut tempus vel, commodo at dui. In hac habitasse platea dictumst. Integer nec ullamcorper purus, tincidunt elementum felis. Duis hendrerit tempor vestibulum. Nunc ut finibus tellus. Donec eu lacus sit amet sem suscipit imperdiet. Quisque cursus vulputate sodales. In sit amet nisl a est lacinia sagittis. </p>
|
||||
|
||||
<img fetchpriority="low" loading="lazy" src="https://picsum.photos/500/500">
|
||||
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed mollis ligula vel nisl pellentesque aliquet. Maecenas eu congue tortor. Nunc mattis ligula vel augue viverra cursus. Suspendisse potenti. Vivamus in risus vitae mi molestie feugiat. Cras sapien tortor, elementum ut tempus vel, commodo at dui. In hac habitasse platea dictumst. Integer nec ullamcorper purus, tincidunt elementum felis. Duis hendrerit tempor vestibulum. Nunc ut finibus tellus. Donec eu lacus sit amet sem suscipit imperdiet. Quisque cursus vulputate sodales. In sit amet nisl a est lacinia sagittis. </p>
|
||||
|
||||
|
||||
`
|
||||
page = Page{
|
||||
PageHeader: PageHeader{
|
||||
UID: uid,
|
||||
Title: "This is my page Title",
|
||||
CoverImageUID: "uid",
|
||||
},
|
||||
Content: content,
|
||||
PageHeader: p,
|
||||
Content: string(html),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package page
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"git.schreifuchs.ch/schreifuchs/schreifuchs.ch/internal/components/images"
|
||||
"github.com/gomarkdown/markdown"
|
||||
"github.com/gomarkdown/markdown/ast"
|
||||
"github.com/gomarkdown/markdown/html"
|
||||
"github.com/gomarkdown/markdown/parser"
|
||||
)
|
||||
|
||||
func (s *Service) getHTML(ctx context.Context, page PageHeader) (out []byte, err error) {
|
||||
extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
|
||||
p := parser.NewWithExtensions(extensions)
|
||||
|
||||
doc := p.Parse(page.md)
|
||||
|
||||
// create HTML renderer with extensions
|
||||
htmlFlags := html.CommonFlags | html.HrefTargetBlank
|
||||
opts := html.RendererOptions{
|
||||
Flags: htmlFlags,
|
||||
RenderNodeHook: imageMiddleware(page),
|
||||
}
|
||||
renderer := html.NewRenderer(opts)
|
||||
|
||||
out = markdown.Render(doc, renderer)
|
||||
return
|
||||
}
|
||||
|
||||
func imageMiddleware(page PageHeader) func(w io.Writer, node ast.Node, entering bool) (ast.WalkStatus, bool) {
|
||||
return func(w io.Writer, node ast.Node, entering bool) (ast.WalkStatus, bool) {
|
||||
if !entering {
|
||||
return ast.GoToNext, false
|
||||
}
|
||||
img, ok := node.(*ast.Image)
|
||||
if !ok {
|
||||
return ast.GoToNext, false
|
||||
}
|
||||
src := string(img.Destination)
|
||||
if strings.HasPrefix(src, ".attachments") {
|
||||
imgPath, err := url.PathUnescape(src)
|
||||
if err != nil {
|
||||
slog.Error("could not unescape path", "err", err)
|
||||
return ast.GoToNext, false
|
||||
}
|
||||
src, err = images.URLFromPath(page.UID + "/" + imgPath)
|
||||
if err != nil {
|
||||
slog.Error("could not get image url", "err", err)
|
||||
return ast.GoToNext, false
|
||||
}
|
||||
|
||||
img.Attribute = &ast.Attribute{Attrs: map[string][]byte{
|
||||
"srcset": []byte(images.SourceSet(src)),
|
||||
"src": []byte(src),
|
||||
}}
|
||||
// // img.Attrs["srcset"] =
|
||||
|
||||
}
|
||||
|
||||
img.Destination = []byte(src)
|
||||
|
||||
return ast.GoToNext, false
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
package page
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/flate"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
@@ -62,12 +59,12 @@ func (s *Service) getPageHeaders(ctx context.Context, uid string) (page PageHead
|
||||
|
||||
slog.Debug("loaded page infos", "cover", coverImage, "content", contentMD)
|
||||
|
||||
content, err := s.fs.Read(contentMD.Path())
|
||||
page.md, err = s.fs.Read(contentMD.Path())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
title := titleRGX.FindStringSubmatch(string(content))
|
||||
title := titleRGX.FindStringSubmatch(string(page.md))
|
||||
if len(title) < 2 {
|
||||
err = fmt.Errorf("%w: no matches for title", ErrMalFormedInput)
|
||||
return
|
||||
@@ -81,14 +78,3 @@ func (s *Service) getPageHeaders(ctx context.Context, uid string) (page PageHead
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getImageUID(path string) string {
|
||||
var b bytes.Buffer
|
||||
// NewWriter with NoDict (nil) creates a raw DEFLATE compressor
|
||||
zw, _ := flate.NewWriter(&b, flate.BestCompression)
|
||||
|
||||
zw.Write([]byte(path))
|
||||
zw.Close() // Essential to flush the final bits
|
||||
|
||||
return base64.RawURLEncoding.EncodeToString(b.Bytes())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user