feat: title on pages
This commit is contained in:
@@ -30,6 +30,7 @@ func (s *Service) getMime(path string) (mimeType string, err error) {
|
||||
|
||||
if mimer, ok := info.(interface{ ContentType() string }); ok {
|
||||
mimeType = mimer.ContentType()
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package images_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"git.schreifuchs.ch/schreifuchs/schreifuchs.ch/internal/components/images"
|
||||
"git.schreifuchs.ch/schreifuchs/schreifuchs.ch/internal/pkg/config"
|
||||
"git.schreifuchs.ch/schreifuchs/schreifuchs.ch/test/testdata"
|
||||
"github.com/valkey-io/valkey-go"
|
||||
"github.com/valkey-io/valkey-go/mock"
|
||||
"go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
func Setup(ctx context.Context, ctrl *gomock.Controller) (*images.Service, *mock.Client) {
|
||||
valkey := mock.NewClient(ctrl)
|
||||
return images.New(testdata.FS(), &config.ImageConfig{Concurency: 1, Quality: 80}, valkey), valkey
|
||||
}
|
||||
|
||||
func BenchmarkService_GetImage(b *testing.B) {
|
||||
srv, valkeyClient := Setup(b.Context(), gomock.NewController(b))
|
||||
uid, err := images.UIDFromPath("cover.jpg")
|
||||
if err != nil {
|
||||
b.Error("could not get uid", err)
|
||||
}
|
||||
|
||||
b.ReportAllocs()
|
||||
for b.Loop() {
|
||||
valkeyClient.EXPECT().Do(gomock.Any(), gomock.Any()).Return(mock.ErrorResult(errors.New("adf")))
|
||||
valkeyClient.EXPECT().Do(gomock.Any(), gomock.Any()).Return(mock.Result(valkey.ValkeyMessage{}))
|
||||
_, _, err = srv.GetImage(b.Context(), uid, images.Options{Width: 500, Quality: 80})
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,11 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
sourceSetSteps = 300
|
||||
sourceSetMax = 1500
|
||||
)
|
||||
|
||||
func UIDFromPath(path string) (uid string, err error) {
|
||||
var b bytes.Buffer
|
||||
// NewWriter with NoDict (nil) creates a raw DEFLATE compressor
|
||||
@@ -57,14 +62,11 @@ func PathFromUID(uid string) (string, error) {
|
||||
func SourceSet(src string) string {
|
||||
sb := strings.Builder{}
|
||||
|
||||
const steps = 300
|
||||
const max = 1500
|
||||
|
||||
i := 1
|
||||
for {
|
||||
width := i * steps
|
||||
width := i * sourceSetSteps
|
||||
sb.WriteString(fmt.Sprintf("%s?w=%d %dw, ", src, width, width))
|
||||
if width >= max {
|
||||
if width >= sourceSetMax {
|
||||
return sb.String()
|
||||
}
|
||||
sb.WriteRune(',')
|
||||
|
||||
@@ -16,6 +16,7 @@ type PageHeader struct {
|
||||
type Page struct {
|
||||
PageHeader
|
||||
Content string
|
||||
Images []Image
|
||||
}
|
||||
|
||||
func (s *Service) GetPages(ctx context.Context) (pages []PageHeader, err error) {
|
||||
@@ -46,7 +47,7 @@ func (s *Service) GetPage(ctx context.Context, uid string) (page Page, err error
|
||||
return
|
||||
}
|
||||
|
||||
html, err := s.getHTML(ctx, p)
|
||||
html, imgs, err := s.getHTML(ctx, p)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -54,6 +55,7 @@ func (s *Service) GetPage(ctx context.Context, uid string) (page Page, err error
|
||||
page = Page{
|
||||
PageHeader: p,
|
||||
Content: string(html),
|
||||
Images: imgs,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -14,7 +14,13 @@ import (
|
||||
"github.com/gomarkdown/markdown/parser"
|
||||
)
|
||||
|
||||
func (s *Service) getHTML(ctx context.Context, page PageHeader) (out []byte, err error) {
|
||||
// image can be used to preload
|
||||
type Image struct {
|
||||
SrcSet string
|
||||
Src string
|
||||
}
|
||||
|
||||
func (s *Service) getHTML(ctx context.Context, page PageHeader) (out []byte, imgs []Image, err error) {
|
||||
extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
|
||||
p := parser.NewWithExtensions(extensions)
|
||||
|
||||
@@ -24,7 +30,7 @@ func (s *Service) getHTML(ctx context.Context, page PageHeader) (out []byte, err
|
||||
htmlFlags := html.CommonFlags | html.HrefTargetBlank
|
||||
opts := html.RendererOptions{
|
||||
Flags: htmlFlags,
|
||||
RenderNodeHook: imageMiddleware(page),
|
||||
RenderNodeHook: imageMiddleware(page, &imgs),
|
||||
}
|
||||
renderer := html.NewRenderer(opts)
|
||||
|
||||
@@ -32,7 +38,7 @@ func (s *Service) getHTML(ctx context.Context, page PageHeader) (out []byte, err
|
||||
return
|
||||
}
|
||||
|
||||
func imageMiddleware(page PageHeader) func(w io.Writer, node ast.Node, entering bool) (ast.WalkStatus, bool) {
|
||||
func imageMiddleware(page PageHeader, imgs *[]Image) 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
|
||||
@@ -53,14 +59,20 @@ func imageMiddleware(page PageHeader) func(w io.Writer, node ast.Node, entering
|
||||
slog.Error("could not get image url", "err", err)
|
||||
return ast.GoToNext, false
|
||||
}
|
||||
image := Image{
|
||||
SrcSet: images.SourceSet(src),
|
||||
Src: src + "?w=1024",
|
||||
}
|
||||
|
||||
img.Attribute = &ast.Attribute{Attrs: map[string][]byte{
|
||||
"srcset": []byte(images.SourceSet(src)),
|
||||
// "srcset": []byte(image.SrcSet),
|
||||
"fetchpriority": []byte("low"),
|
||||
"loading": []byte("lazy"),
|
||||
"class": []byte("min-h-48"),
|
||||
"src": []byte(src),
|
||||
"src": []byte(image.Src),
|
||||
}}
|
||||
|
||||
*imgs = append(*imgs, image)
|
||||
// // img.Attrs["srcset"] =
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user