diff --git a/fonts/JetBrainsMono-Bold.ttf b/fonts/JetBrainsMono-Bold.ttf
new file mode 100644
index 0000000..710c34b
Binary files /dev/null and b/fonts/JetBrainsMono-Bold.ttf differ
diff --git a/fonts/JetBrainsMono-BoldItalic.ttf b/fonts/JetBrainsMono-BoldItalic.ttf
new file mode 100644
index 0000000..fdff00f
Binary files /dev/null and b/fonts/JetBrainsMono-BoldItalic.ttf differ
diff --git a/fonts/JetBrainsMono-ExtraBold.ttf b/fonts/JetBrainsMono-ExtraBold.ttf
new file mode 100644
index 0000000..eb94300
Binary files /dev/null and b/fonts/JetBrainsMono-ExtraBold.ttf differ
diff --git a/fonts/JetBrainsMono-ExtraBoldItalic.ttf b/fonts/JetBrainsMono-ExtraBoldItalic.ttf
new file mode 100644
index 0000000..b70b4e7
Binary files /dev/null and b/fonts/JetBrainsMono-ExtraBoldItalic.ttf differ
diff --git a/fonts/JetBrainsMono-ExtraLight.ttf b/fonts/JetBrainsMono-ExtraLight.ttf
new file mode 100644
index 0000000..74efced
Binary files /dev/null and b/fonts/JetBrainsMono-ExtraLight.ttf differ
diff --git a/fonts/JetBrainsMono-ExtraLightItalic.ttf b/fonts/JetBrainsMono-ExtraLightItalic.ttf
new file mode 100644
index 0000000..1a9d2d3
Binary files /dev/null and b/fonts/JetBrainsMono-ExtraLightItalic.ttf differ
diff --git a/fonts/JetBrainsMono-Italic.ttf b/fonts/JetBrainsMono-Italic.ttf
new file mode 100644
index 0000000..ffd5d77
Binary files /dev/null and b/fonts/JetBrainsMono-Italic.ttf differ
diff --git a/fonts/JetBrainsMono-Light.ttf b/fonts/JetBrainsMono-Light.ttf
new file mode 100644
index 0000000..c0682f9
Binary files /dev/null and b/fonts/JetBrainsMono-Light.ttf differ
diff --git a/fonts/JetBrainsMono-LightItalic.ttf b/fonts/JetBrainsMono-LightItalic.ttf
new file mode 100644
index 0000000..f20bac9
Binary files /dev/null and b/fonts/JetBrainsMono-LightItalic.ttf differ
diff --git a/fonts/JetBrainsMono-Medium.ttf b/fonts/JetBrainsMono-Medium.ttf
new file mode 100644
index 0000000..17ff945
Binary files /dev/null and b/fonts/JetBrainsMono-Medium.ttf differ
diff --git a/fonts/JetBrainsMono-MediumItalic.ttf b/fonts/JetBrainsMono-MediumItalic.ttf
new file mode 100644
index 0000000..9b699bb
Binary files /dev/null and b/fonts/JetBrainsMono-MediumItalic.ttf differ
diff --git a/fonts/JetBrainsMono-Regular.ttf b/fonts/JetBrainsMono-Regular.ttf
new file mode 100644
index 0000000..9a5202e
Binary files /dev/null and b/fonts/JetBrainsMono-Regular.ttf differ
diff --git a/fonts/JetBrainsMono-SemiBold.ttf b/fonts/JetBrainsMono-SemiBold.ttf
new file mode 100644
index 0000000..84b7795
Binary files /dev/null and b/fonts/JetBrainsMono-SemiBold.ttf differ
diff --git a/fonts/JetBrainsMono-SemiBoldItalic.ttf b/fonts/JetBrainsMono-SemiBoldItalic.ttf
new file mode 100644
index 0000000..ffa1f39
Binary files /dev/null and b/fonts/JetBrainsMono-SemiBoldItalic.ttf differ
diff --git a/fonts/JetBrainsMono-Thin.ttf b/fonts/JetBrainsMono-Thin.ttf
new file mode 100644
index 0000000..1317bfe
Binary files /dev/null and b/fonts/JetBrainsMono-Thin.ttf differ
diff --git a/fonts/JetBrainsMono-ThinItalic.ttf b/fonts/JetBrainsMono-ThinItalic.ttf
new file mode 100644
index 0000000..bc72439
Binary files /dev/null and b/fonts/JetBrainsMono-ThinItalic.ttf differ
diff --git a/fonts/Nunito-Black.ttf b/fonts/Nunito-Black.ttf
new file mode 100644
index 0000000..e4fe5d0
Binary files /dev/null and b/fonts/Nunito-Black.ttf differ
diff --git a/fonts/Nunito-BlackItalic.ttf b/fonts/Nunito-BlackItalic.ttf
new file mode 100644
index 0000000..e8845a2
Binary files /dev/null and b/fonts/Nunito-BlackItalic.ttf differ
diff --git a/fonts/Nunito-Bold.ttf b/fonts/Nunito-Bold.ttf
new file mode 100644
index 0000000..368468c
Binary files /dev/null and b/fonts/Nunito-Bold.ttf differ
diff --git a/fonts/Nunito-BoldItalic.ttf b/fonts/Nunito-BoldItalic.ttf
new file mode 100644
index 0000000..dfd2b5e
Binary files /dev/null and b/fonts/Nunito-BoldItalic.ttf differ
diff --git a/fonts/Nunito-ExtraBold.ttf b/fonts/Nunito-ExtraBold.ttf
new file mode 100644
index 0000000..8f5e1f6
Binary files /dev/null and b/fonts/Nunito-ExtraBold.ttf differ
diff --git a/fonts/Nunito-ExtraBoldItalic.ttf b/fonts/Nunito-ExtraBoldItalic.ttf
new file mode 100644
index 0000000..51f1f11
Binary files /dev/null and b/fonts/Nunito-ExtraBoldItalic.ttf differ
diff --git a/fonts/Nunito-ExtraLight.ttf b/fonts/Nunito-ExtraLight.ttf
new file mode 100644
index 0000000..251c471
Binary files /dev/null and b/fonts/Nunito-ExtraLight.ttf differ
diff --git a/fonts/Nunito-ExtraLightItalic.ttf b/fonts/Nunito-ExtraLightItalic.ttf
new file mode 100644
index 0000000..10e5df7
Binary files /dev/null and b/fonts/Nunito-ExtraLightItalic.ttf differ
diff --git a/fonts/Nunito-Italic.ttf b/fonts/Nunito-Italic.ttf
new file mode 100644
index 0000000..871a9dd
Binary files /dev/null and b/fonts/Nunito-Italic.ttf differ
diff --git a/fonts/Nunito-Light.ttf b/fonts/Nunito-Light.ttf
new file mode 100644
index 0000000..ad56724
Binary files /dev/null and b/fonts/Nunito-Light.ttf differ
diff --git a/fonts/Nunito-LightItalic.ttf b/fonts/Nunito-LightItalic.ttf
new file mode 100644
index 0000000..f1664ed
Binary files /dev/null and b/fonts/Nunito-LightItalic.ttf differ
diff --git a/fonts/Nunito-Regular.ttf b/fonts/Nunito-Regular.ttf
new file mode 100644
index 0000000..c8c90b7
Binary files /dev/null and b/fonts/Nunito-Regular.ttf differ
diff --git a/fonts/Nunito-SemiBold.ttf b/fonts/Nunito-SemiBold.ttf
new file mode 100644
index 0000000..3a30359
Binary files /dev/null and b/fonts/Nunito-SemiBold.ttf differ
diff --git a/fonts/Nunito-SemiBoldItalic.ttf b/fonts/Nunito-SemiBoldItalic.ttf
new file mode 100644
index 0000000..76fa99d
Binary files /dev/null and b/fonts/Nunito-SemiBoldItalic.ttf differ
diff --git a/fonts/OFL.txt b/fonts/OFL.txt
new file mode 100644
index 0000000..9a43a3a
--- /dev/null
+++ b/fonts/OFL.txt
@@ -0,0 +1,93 @@
+Copyright 2014 The Nunito Project Authors (https://github.com/googlefonts/nunito)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/go.mod b/go.mod
index b2f974d..5e680da 100644
--- a/go.mod
+++ b/go.mod
@@ -4,12 +4,15 @@ go 1.15
require (
github.com/aymerick/raymond v2.0.2+incompatible
+ github.com/fogleman/gg v1.3.0 // indirect
+ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/mitchellh/mapstructure v1.4.1
github.com/rjeczalik/notify v0.9.2
github.com/wellington/go-libsass v0.9.2
github.com/yuin/goldmark v1.3.1
github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691
github.com/yuin/goldmark-meta v1.0.0
+ golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46 // indirect
)
diff --git a/go.sum b/go.sum
index f02640b..dc3a512 100644
--- a/go.sum
+++ b/go.sum
@@ -23,6 +23,10 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
+github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
+github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/gorilla/csrf v1.6.0/go.mod h1:7tSf8kmjNYr7IWDCYhd3U8Ck34iQ/Yw5CJu7bAkHEGI=
github.com/gorilla/handlers v1.4.1/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
@@ -60,6 +64,8 @@ github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691 h1:VWSx
github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691/go.mod h1:YLF3kDffRfUH/bTxOxHhV6lxwIB3Vfj91rEwNMS9MXo=
github.com/yuin/goldmark-meta v1.0.0 h1:ScsatUIT2gFS6azqzLGUjgOnELsBOxMXerM3ogdJhAM=
github.com/yuin/goldmark-meta v1.0.0/go.mod h1:zsNNOrZ4nLuyHAJeLQEZcQat8dm70SmB2kHbls092Gc=
+golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
+golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -69,6 +75,7 @@ golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46 h1:V066+OYJ66oTjnhm4Yrn7SXIw
golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/post.go b/post.go
index 13e920c..966a00b 100644
--- a/post.go
+++ b/post.go
@@ -31,6 +31,7 @@ type Post struct {
Slug string
Metadata Metadata
Contents string
+ Image bytes.Buffer
}
func newPost(slug string) (*Post, error) {
@@ -73,6 +74,12 @@ func newPost(slug string) (*Post, error) {
Contents: converted.String(),
}
+ url := blogURL + "/" + slug
+ err = createImage(post.Metadata.Title, post.Metadata.Summary, url, &post.Image)
+ if err != nil {
+ return nil, fmt.Errorf("could not create post image: %v", err)
+ }
+
return post, nil
}
diff --git a/server.go b/server.go
index d0c8139..43608a6 100644
--- a/server.go
+++ b/server.go
@@ -1,12 +1,22 @@
package main
import (
+ "bytes"
+ "io"
"log"
+ "math"
"net/http"
"strings"
"sync"
"github.com/aymerick/raymond"
+ "github.com/fogleman/gg"
+)
+
+const (
+ blogTitle = "Prose"
+ blogURL = "https://prose.nsood.in"
+ blogSummary = "Where I infodump in Markdown and nobody can stop me."
)
type server struct {
@@ -15,7 +25,8 @@ type server struct {
mu sync.RWMutex
templates map[string]*raymond.Template
postList
- styles map[string]string
+ styles map[string]string
+ homeImage bytes.Buffer
}
func newServer() (*server, error) {
@@ -23,6 +34,11 @@ func newServer() (*server, error) {
staticHandler: http.FileServer(http.Dir("static/")),
}
+ err := createImage(blogTitle, blogSummary, blogURL, &s.homeImage)
+ if err != nil {
+ return nil, err
+ }
+
posts, err := newPostList()
if err != nil {
return nil, err
@@ -92,11 +108,18 @@ func (s *server) router(res http.ResponseWriter, req *http.Request) {
s.homePage(res, req)
return
}
+ if slug == "about.png" {
+ s.renderImage(res, req, &s.homeImage)
+ return
+ }
for _, p := range s.postList {
- if p.Slug == slug {
+ if slug == p.Slug {
s.postPage(p, res, req)
return
+ } else if slug == p.Slug+"/about.png" {
+ s.renderImage(res, req, &p.Image)
+ return
}
}
@@ -152,7 +175,7 @@ func (s *server) homePage(res http.ResponseWriter, req *http.Request) {
posts = posts + summary
}
- page, err := s.createWebPage("Home", "Where I infodump in Markdown and nobody can stop me.", posts)
+ page, err := s.createWebPage("Home", blogSummary, posts)
if err != nil {
s.errorInRequest(res, req, err)
@@ -161,6 +184,14 @@ func (s *server) homePage(res http.ResponseWriter, req *http.Request) {
res.Write([]byte(page))
}
+func (s *server) renderImage(res http.ResponseWriter, req *http.Request, img io.Reader) {
+ res.Header().Add("content-type", "image/png")
+ _, err := io.Copy(res, img)
+ if err != nil {
+ s.errorInRequest(res, req, err)
+ }
+}
+
func (s *server) loadStylesheet(res http.ResponseWriter, req *http.Request, filename string) (ok bool) {
contents, ok := s.styles[filename]
if !ok {
@@ -170,3 +201,74 @@ func (s *server) loadStylesheet(res http.ResponseWriter, req *http.Request, file
res.Write([]byte(contents))
return ok
}
+
+func createImage(title, summary, url string, out io.Writer) error {
+ imgWidth, imgPaddingX, imgPaddingY := 800, 30, 60
+ titleSize, summarySize, urlSize := 42.0, 28.0, 18.0
+ lineHeight := 1.5
+ textWidth := float64(imgWidth - 2*imgPaddingX)
+
+ // temporarily set height = 0 for context only used to generate
+ // wrapped strings
+ draw := gg.NewContext(imgWidth, 0)
+
+ titleFont, err := gg.LoadFontFace("fonts/Nunito-Bold.ttf", titleSize)
+ if err != nil {
+ return err
+ }
+ summaryFont, err := gg.LoadFontFace("fonts/Nunito-LightItalic.ttf", summarySize)
+ if err != nil {
+ return err
+ }
+ urlFont, err := gg.LoadFontFace("fonts/JetBrainsMono-ExtraLight.ttf", urlSize)
+ if err != nil {
+ return err
+ }
+
+ draw.SetFontFace(titleFont)
+ wrappedTitle := draw.WordWrap(title, textWidth)
+ draw.SetFontFace(summaryFont)
+ wrappedSummary := draw.WordWrap(summary, textWidth)
+
+ imgHeight := 2 * imgPaddingY
+ for range wrappedTitle {
+ imgHeight += int(math.Ceil(lineHeight * titleSize))
+ }
+ for range wrappedSummary {
+ imgHeight += int(math.Ceil(lineHeight * summarySize))
+ }
+ imgHeight += int(math.Ceil(lineHeight * urlSize))
+
+ // actual context with actual height
+ draw = gg.NewContext(imgWidth, imgHeight)
+ draw.SetHexColor("#fff")
+ draw.DrawRectangle(0, 0, float64(imgWidth), float64(imgHeight))
+ draw.Fill()
+ draw.SetHexColor("#3498db")
+ accentHeight := 5.0
+ draw.DrawRectangle(0, float64(imgHeight)-accentHeight, float64(imgWidth), accentHeight)
+ draw.Fill()
+
+ offset := float64(imgPaddingY)
+
+ draw.SetFontFace(titleFont)
+ draw.SetHexColor("#333")
+ for _, line := range wrappedTitle {
+ draw.DrawString(line, float64(imgPaddingX), offset)
+ offset += lineHeight * titleSize
+ }
+
+ draw.SetFontFace(summaryFont)
+ draw.SetHexColor("#999")
+ for _, line := range wrappedSummary {
+ draw.DrawString(line, float64(imgPaddingX), offset)
+ offset += lineHeight * summarySize
+ }
+
+ draw.SetHexColor("#333")
+ draw.SetFontFace(urlFont)
+ urlY := float64(imgHeight - imgPaddingY)
+ draw.DrawStringWrapped(url, float64(imgPaddingX), urlY, 0, 0, textWidth, lineHeight, gg.AlignRight)
+
+ return draw.EncodePNG(out)
+}
diff --git a/templates/page.html b/templates/page.html
index 0d06202..8658c56 100644
--- a/templates/page.html
+++ b/templates/page.html
@@ -8,6 +8,7 @@
+