From d34755145559cb2f28b873e803ca6349b773287c Mon Sep 17 00:00:00 2001 From: Naman Sood Date: Mon, 15 Feb 2021 02:31:18 -0500 Subject: [PATCH] Load HTML templates and SCSS styling --- README.md | 2 +- go.mod | 10 +- go.sum | 60 ++++++++ page.go | 61 ++++++-- server.go | 121 ++++++++++++++-- static/.gitignore | 1 + styles/main.scss | 306 ++++++++++++++++++++++++++++++++++++++++ templates/fullpost.html | 9 ++ templates/page.html | 27 ++++ templates/summary.html | 6 + 10 files changed, 581 insertions(+), 22 deletions(-) create mode 100644 static/.gitignore create mode 100644 styles/main.scss create mode 100644 templates/fullpost.html create mode 100644 templates/page.html create mode 100644 templates/summary.html diff --git a/README.md b/README.md index b7c793e..21a643d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Prose is a blogging platform written in Go, which I am building to serve my own ## Usage -Blog posts should be created in the format `DATE-title-slug.md`. Work in progress posts should be stored as `WIP-title-slug.md`. Static content should be stored in the `static/` folder, appropriately arranged. +Blog posts should be created in the format `title-slug.md`. Work in progress posts should be stored as `WIP-title-slug.md`. Static content should be stored in the `static/` folder, appropriately arranged. Posts will be served as `/title-slug`, and files like `static/random/file/structure.txt` will be served as `/random/file/structure.txt`. When title slugs and static files conflict, slugs will have higher precdence. diff --git a/go.mod b/go.mod index e90b934..43db5bf 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,12 @@ module prose go 1.15 -require github.com/yuin/goldmark v1.3.1 +require ( + github.com/aymerick/raymond v2.0.2+incompatible + github.com/mitchellh/mapstructure v1.4.1 + 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/net v0.0.0-20210119194325-5f4716e94777 // indirect +) diff --git a/go.sum b/go.sum index de9bccb..2de3205 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,60 @@ +github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI= +github.com/alecthomas/chroma v0.7.2-0.20200305040604-4f3623dce67a h1:3v1NrYWWqp2S72e4HLgxKt83B3l0lnORDholH/ihoMM= +github.com/alecthomas/chroma v0.7.2-0.20200305040604-4f3623dce67a/go.mod h1:fv5SzZPFJbwp2NXJWpFIX7DZS4HgV1K4ew4Pc2OZD9s= +github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= +github.com/alecthomas/kong v0.1.17-0.20190424132513-439c674f7ae0/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI= +github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI= +github.com/alecthomas/kong-hcl v0.1.8-0.20190615233001-b21fea9723c8/go.mod h1:MRgZdU3vrFd05IQ89AxUZ0aYdF39BYoNFa324SodPCA= +github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= +github.com/aymerick/raymond v1.1.0 h1:phuNN2s67eI/HtO8CrvqFcdR2JP+BtkGJZ9n692Hr2Y= +github.com/aymerick/raymond v2.0.2+incompatible h1:VEp3GpgdAnv9B2GFyTvqgcKvY+mfKMjPOA3SbKLtnU0= +github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= +github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= +github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ= +github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/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= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/wellington/go-libsass v0.9.2 h1:6Ims04UDdBs6/CGSVK5JC8FNikR5ssrsMMKE/uaO5Q8= +github.com/wellington/go-libsass v0.9.2/go.mod h1:mxgxgam0N0E+NAUMHLcu20Ccfc3mVpDkyrLDayqfiTs= +github.com/yuin/goldmark v1.1.22/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.1 h1:eVwehsLsZlCJCwXyGLgg+Q4iFWE/eTIMG0e8waCmm/I= github.com/yuin/goldmark v1.3.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691 h1:VWSxtAiQNh3zgHJpdpkpVYjTPqRE3P6UZCOPa1nRDio= +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= gitlab.com/golang-commonmark/html v0.0.0-20191124015941-a22733972181 h1:K+bMSIx9A7mLES1rtG+qKduLIXq40DAzYHtb0XuCukA= gitlab.com/golang-commonmark/html v0.0.0-20191124015941-a22733972181/go.mod h1:dzYhVIwWCtzPAa4QP98wfB9+mzt33MSmM8wsKiMi2ow= gitlab.com/golang-commonmark/linkify v0.0.0-20191026162114-a0c2df6c8f82 h1:oYrL81N608MLZhma3ruL8qTM4xcpYECGut8KSxRY59g= @@ -17,8 +68,17 @@ gitlab.com/golang-commonmark/mdurl v0.0.0-20191124015652-932350d1cb84/go.mod h1: gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f h1:Wku8eEdeJqIOFHtrfkYUByc4bCaTeA6fL0UJgfEiFMI= gitlab.com/golang-commonmark/puny v0.0.0-20191124015043-9f83538fa04f/go.mod h1:Tiuhl+njh/JIg0uS/sOJVYi0x2HEa5rc1OAaVsb5tAs= gitlab.com/opennota/wd v0.0.0-20180912061657-c5d65f63c638/go.mod h1:EGRJaqe2eO9XGmFtQCvV3Lm9NLico3UhFwUpCG/+mVU= +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-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/page.go b/page.go index 56da3bf..c3ae948 100644 --- a/page.go +++ b/page.go @@ -5,33 +5,74 @@ import ( "fmt" "io/ioutil" + "github.com/aymerick/raymond" + "github.com/mitchellh/mapstructure" "github.com/yuin/goldmark" + highlighting "github.com/yuin/goldmark-highlighting" + meta "github.com/yuin/goldmark-meta" "github.com/yuin/goldmark/extension" + "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/renderer/html" ) -type page struct { - slug string +// Metadata stores the data about a page that needs to be visible +// at the home page. +type Metadata struct { + Title string + Summary string + Date string // TODO: better representation? time.Time might cause timezone issues... } -func (p *page) render() ([]byte, error) { - data, err := ioutil.ReadFile("posts/" + p.slug + ".md") +// Page stores the contents of a blog post. +type Page struct { + Slug string + Metadata Metadata + Contents string +} + +func newPage(slug string) (*Page, error) { + data, err := ioutil.ReadFile("posts/" + slug + ".md") if err != nil { - return nil, fmt.Errorf("Could not read from %s.md: %s", p.slug, err) + return nil, fmt.Errorf("could not read file: %s", err) } md := goldmark.New( - goldmark.WithExtensions(extension.Linkify), + goldmark.WithExtensions( + extension.Linkify, + extension.Strikethrough, + extension.Typographer, + meta.Meta, + highlighting.Highlighting, + ), goldmark.WithRendererOptions( html.WithUnsafe(), ), ) - var converted bytes.Buffer - err = md.Convert(data, &converted) + ctx := parser.NewContext() + err = md.Convert(data, &converted, parser.WithContext(ctx)) if err != nil { - return nil, fmt.Errorf("Could not parse markdown from %s.md: %s", p.slug, err) + return nil, fmt.Errorf("could not parse markdown: %s", err) + } + mdMap, err := meta.TryGet(ctx) + if err != nil { + return nil, fmt.Errorf("could not parse metadata: %s", err) + } + var metadata Metadata + err = mapstructure.Decode(mdMap, &metadata) + if err != nil { + return nil, fmt.Errorf("could not destructure metadata: %s", err) } - return converted.Bytes(), nil + page := &Page{ + Slug: slug, + Metadata: metadata, + Contents: converted.String(), + } + + return page, nil +} + +func (p *Page) render(tpl *raymond.Template) (string, error) { + return tpl.Exec(p) } diff --git a/server.go b/server.go index 06441f7..d67efab 100644 --- a/server.go +++ b/server.go @@ -2,15 +2,23 @@ package main import ( "fmt" + "io" "io/ioutil" "log" "net/http" + "os" "strings" + + "github.com/aymerick/raymond" + "github.com/wellington/go-libsass" ) type server struct { - pages []page + pages []*Page staticHandler http.Handler + pageTpl *raymond.Template + fullPostTpl *raymond.Template + summaryTpl *raymond.Template } func newServer() (*server, error) { @@ -21,7 +29,7 @@ func newServer() (*server, error) { } s := &server{ - pages: make([]page, 0, len(files)), + pages: make([]*Page, 0, len(files)), staticHandler: http.FileServer(http.Dir("static/")), } @@ -29,10 +37,73 @@ func newServer() (*server, error) { filename := f.Name() if strings.HasSuffix(filename, ".md") { - s.pages = append(s.pages, page{slug: strings.TrimSuffix(filename, ".md")}) + page, err := newPage(strings.TrimSuffix(filename, ".md")) + if err != nil { + return nil, fmt.Errorf("could not render %s: %s", filename, err) + } + s.pages = append(s.pages, page) + log.Printf("Loaded page %s", filename) } } + s.pageTpl, err = raymond.ParseFile("templates/page.html") + if err != nil { + return nil, fmt.Errorf("could not parse page template") + } + log.Printf("Loaded page template") + + s.fullPostTpl, err = raymond.ParseFile("templates/fullpost.html") + if err != nil { + return nil, fmt.Errorf("could not parse full post template") + } + log.Printf("Loaded full post template") + + s.summaryTpl, err = raymond.ParseFile("templates/summary.html") + if err != nil { + return nil, fmt.Errorf("could not parse summary template") + } + log.Printf("Loaded summary template") + + styles, err := ioutil.ReadDir("styles/") + if err != nil { + return nil, fmt.Errorf("Could not load styles directory: %s", err) + } + + for _, s := range styles { + filename := s.Name() + in, err := os.Open("styles/" + filename) + if err != nil { + return nil, fmt.Errorf("Could not open style infile %s: %s", filename, err) + } + if strings.HasSuffix(filename, ".scss") { + outFilename := strings.TrimSuffix(filename, ".scss") + ".css" + out, err := os.Create("static/css/" + outFilename) + if err != nil { + return nil, fmt.Errorf("Could not open style outfile %s: %s", outFilename, err) + } + comp, err := libsass.New(out, in) + if err != nil { + return nil, fmt.Errorf("Could not start sass compiler for file %s: %s", filename, err) + } + if err = comp.Run(); err != nil { + return nil, fmt.Errorf("Could not generate stylesheet %s: %s", filename, err) + } + } else if strings.HasSuffix(filename, ".css") { + out, err := os.Create("static/css/" + filename) + if err != nil { + return nil, fmt.Errorf("Could not open style outfile %s: %s", filename, err) + } + _, err = io.Copy(out, in) + if err != nil { + return nil, fmt.Errorf("Could not copy stylesheet %s: %s", filename, err) + } + } else { + log.Printf("Skipping stylesheet %s, don't know how to handle", filename) + continue + } + log.Printf("Loaded stylesheet %s", filename) + } + return s, nil } @@ -50,16 +121,20 @@ func (s *server) router(res http.ResponseWriter, req *http.Request) { } for _, p := range s.pages { - if p.slug == slug { - buf, err := p.render() + if p.Slug == slug { + res.Header().Add("content-type", "text/html") + contents, err := p.render(s.fullPostTpl) if err != nil { - res.WriteHeader(http.StatusInternalServerError) - res.Write([]byte("oh no")) + s.errorInRequest(res, req, err) } - res.Write(buf) + page, err := s.createPage(p.Metadata.Title, contents) + if err != nil { + s.errorInRequest(res, req, err) + } + res.Write([]byte(page)) return } } @@ -67,12 +142,38 @@ func (s *server) router(res http.ResponseWriter, req *http.Request) { s.staticHandler.ServeHTTP(res, req) } +func (s *server) errorInRequest(res http.ResponseWriter, req *http.Request, err error) { + res.WriteHeader(http.StatusInternalServerError) + res.Write([]byte("oh no")) + log.Printf("ERR %s: %s", req.URL.Path, err) +} + +func (s *server) createPage(title, contents string) (string, error) { + ctx := map[string]interface{}{ + "title": title, + "contents": contents, + } + return s.pageTpl.Exec(ctx) +} + func (s *server) homePage(res http.ResponseWriter, req *http.Request) { res.Header().Add("content-type", "text/html") - res.Write([]byte("

blog

")) + var posts string for _, p := range s.pages { - fmt.Fprintf(res, "%s
", p.slug, p.slug) + summary, err := p.render(s.summaryTpl) + if err != nil { + log.Printf("could not render page summary for %s", p.Slug) + } + posts = posts + summary } + + page, err := s.createPage("Home", posts) + + if err != nil { + s.errorInRequest(res, req, err) + } + + res.Write([]byte(page)) } diff --git a/static/.gitignore b/static/.gitignore new file mode 100644 index 0000000..493ec68 --- /dev/null +++ b/static/.gitignore @@ -0,0 +1 @@ +css \ No newline at end of file diff --git a/styles/main.scss b/styles/main.scss new file mode 100644 index 0000000..e0901b5 --- /dev/null +++ b/styles/main.scss @@ -0,0 +1,306 @@ +*, *:before, *:after { + box-sizing: border-box; +} + +@mixin transition-all { + transition: all 0.1s ease-in-out; +} + +html { + font-size: 14pt; + min-height: 100%; + position: relative; +} + +$ls: 1.4rem; + +$darkMode: true; + + + +$bgColor: white; +$bodyColor: #555; +$strongColor: #333; +$lightColor: #999; +$accentColor: #3498db; + +body { + height: 100%; + background-color: $bgColor; + font-family: 'Nunito', sans-serif; + margin: 0; + color: $bodyColor; +} + +.grid { + position: absolute; + height: 100%; + width: 100%; + top: 0; + left: 0; + z-index: 5000; + background-image: linear-gradient(transparent 93%, rgba(0,0,0,0.3) 93%, rgba(0,0,0,0.3)); + background-size: 1*$ls 1*$ls; + pointer-events: none; + + &.hidden { + display: none; + } +} + +button.grid-button { + position: fixed; + bottom: 0.5*$ls; + right: 0.5*$ls; + height: 2*$ls; + padding: 0 1*$ls; + margin: 0; + border: 0; + outline: none; + font: inherit; + font-size: 0.8rem; + background: $accentColor; + color: white; + z-index: 6000; + border-radius: 0.2*$ls; + box-shadow: 0 0.1*$ls 0.1*$ls 0.0125*$ls rgba(0,0,0,0.3); +} + +header { + height: 3*$ls; + display: flex; + align-items: center; + justify-content: space-between; + width: 40*$ls; + max-width: 100%; + margin: 0 auto; + + h1.title { + margin: 0; + line-height: 3*$ls; + color: $strongColor; + font-size: 1.8rem; + padding: 0; + } + + img { + height: 80%; + margin: 0 0.5*$ls; + } + + nav { + display: flex; + height: 100%; + + a { + color: $strongColor; + text-decoration: none; + display: block; + line-height: 3*$ls; + padding: 0 $ls; + position: relative; + height: 100%; + + &:before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 0.15rem; + background: white; + opacity: 0; + @include transition-all; + } + + &:hover:before { + opacity: 1; + } + } + } +} + +main { + width: 40*$ls; + max-width: 100%; + margin: 4*$ls auto 2*$ls; +} + +article { + padding: 2*$ls; + //background: white; + //box-shadow: 0 0.05*$ls 0.1*$ls rgba(0,0,0,0.5); + border-radius: 0.2*$ls; + margin: 1*$ls 0 0; + + date { + font-size: 0.9rem; + height: $ls; + line-height: $ls; + display: block; + font-weight: 400; + } + + h1 { + font-size: 2.6rem; + margin: 0; + line-height: 2*$ls; + color: $strongColor; + } + + h2 { + font-size: 1.4rem; + font-weight: 300; + font-style: italic; + color: $lightColor; + line-height: 1*$ls; + margin: 1*$ls 0 0; + } + + h3 { + line-height: $ls; + margin: $ls 0; + font-size: 1.3rem; + color: $strongColor; + } + + h4 { + line-height: $ls; + margin: $ls 0; + font-size: 1rem; + color: $strongColor; + } + + p { + line-height: $ls; + margin: $ls 0 0; + color: $bodyColor; + } + + + blockquote { + margin: $ls 0; + padding: 0 $ls; + border-left: 0.2rem solid $lightColor; + color: $lightColor; + font-style: italic; + + p { + margin: 0; + } + } + + code { + font-family: 'JetBrains Mono', monospace; + font-size: 0.9em; + color: $strongColor; + } + + pre { + margin: $ls 0; + line-height: $ls; + max-width: 100%; + overflow-x: auto; + padding: 0 2*$ls; + + code { + line-height: $ls; + display: block; + } + } + + figure { + height: 20*$ls; + padding-bottom: 2*$ls; + margin: 2*$ls 0 0; + + img { + height: 100%; + width: 100%; + display: block; + object-fit: contain; + } + + img.fill { + object-fit: cover; + } + + figcaption { + height: 2*$ls; + line-height: 2*$ls; + text-align: center; + font-style: italic; + color: $lightColor; + font-size: 0.8rem; + } + } + + section.content { + a { + color: $strongColor; + text-decoration: none; + background-image: linear-gradient( + transparent 80%, + $lightColor 80%, + $lightColor 85%, + transparent 85% + ); + + &:hover { + color: $bodyColor; + background-image: linear-gradient( + transparent 80%, + lighten($lightColor, 15%) 80%, + lighten($lightColor, 15%) 85%, + transparent 85% + ); + } + } + + ul, ol { + color: $bodyColor; + margin: $ls 0; + padding: 0 0 0 $ls; + line-height: $ls; + + ul, ol { + margin: 0; + } + } + + ul { + li { + list-style: none; + position: relative; + + &:before { + content: 'ยท'; + height: $ls; + width: $ls; + display: block; + position: absolute; + top: 0; + left: -$ls; + text-align: center; + line-height: $ls; + font-weight: bold; + color: $strongColor; + } + } + } + } + + a.load-content { + display: block; + height: 3*$ls; + line-height: 3*$ls; + color: $accentColor; + text-align: center; + text-decoration: none; + } +} + +footer { + text-align: center; + padding: $ls 0; +} \ No newline at end of file diff --git a/templates/fullpost.html b/templates/fullpost.html new file mode 100644 index 0000000..ec14f9f --- /dev/null +++ b/templates/fullpost.html @@ -0,0 +1,9 @@ +
+ {{metadata.date}} +

{{metadata.title}}

+

{{metadata.summary}}

+
+ {{{contents}}} +
+ ← Back home +
\ No newline at end of file diff --git a/templates/page.html b/templates/page.html new file mode 100644 index 0000000..6318384 --- /dev/null +++ b/templates/page.html @@ -0,0 +1,27 @@ + + + + + + + + {{title}} – Prose + + +
+
+

Prose

+ +
+
+ {{{contents}}} +
+ + + \ No newline at end of file diff --git a/templates/summary.html b/templates/summary.html new file mode 100644 index 0000000..9bd0031 --- /dev/null +++ b/templates/summary.html @@ -0,0 +1,6 @@ +
+ {{metadata.date}} +

{{metadata.title}}

+

{{metadata.summary}}

+ Read more → +
\ No newline at end of file