pico
created pr with
pico/142.1
added pico/142.2
1: 18a25e7 ! 1: 1e9cddc style(prose): minimal design ethos
-: ------- > 2: 0967882 chore(prose): remove with_styles and layout front-matter fields
cmds
checkout latest patchset:
ssh pr.pico.sh pull pico:142 | git am -3checkout specific patchset revision:
ssh pr.pico.sh pull pico:142 [rev] | git am -3add changes to patch request:
git format-patch main --stdout | ssh pr.pico.sh pico:142add comment to patch request:
ssh pr.pico.sh comment pico:142 "lgtm!"
Patchset
pico/142.2
style(prose): minimal design ethos
Eric Bower
2026-09-30T13:00:35ZOur previous prose blog design hasn't changed since we initially released prose. The previous design was minimalistic but it still made some assumptions about how a blog should look. In order to support customization we added support for users to upload `_styles.css` and front-matter fields like `with_styles` to provide full customization. The main thesis for this change was trying to answer the question: what if blogs came without styles by default and users are required to theme it themselves? This would make it so we are not in control of the overall theme of the blog and provides full customization for the end-user. As we were experimenting with this design we wanted to include a very minimal css reset so the default design is consistent across browsers. We are also implemented a few rules with this css reset for best practices. This is our new design ethos: - Center content on the screen - 70ch max width - Headers should be anchored to the content they are heading That's it. The rest of the reset file is for consistency across browsers. With this change we are also disabling the `with_styles` field to encourage people to preserve this new design ethos. Finally as part of this change we restructured the html tree to better adhere to semantic meaning of those html entities. We were already mostly there but some of the headers and footers were restructured slightly.
Semantic diff summary
0 added,
2 modified,
0 signature changed,
0 removed
across 1 analyzed file
(7 files skipped: unsupported file type)
+1
-4
pkg/apps/prose/api.go
#
| ... | ... | @@ -185,7 +185,6 @@ func blogHandler(w http.ResponseWriter, r *http.Request) { | |
| 185 | 185 | ||
| 186 | 186 | ts, err := router.RenderTemplate(cfg, []string{ | |
| 187 | 187 | cfg.StaticPath("html/blog-default.partial.tmpl"), | |
| 188 | - | cfg.StaticPath("html/blog-aside.partial.tmpl"), | |
| 189 | 188 | cfg.StaticPath("html/blog.page.tmpl"), | |
| 190 | 189 | }) | |
| 191 | 190 |
| ... | ... | @@ -893,9 +892,7 @@ func serveFile(file string, contentType string) http.HandlerFunc { | |
| 893 | 892 | ||
| 894 | 893 | func createStaticRoutes() []router.Route { | |
| 895 | 894 | return []router.Route{ | |
| 896 | - | router.NewRoute("GET", "/main.css", serveFile("main.css", "text/css")), | |
| 897 | - | router.NewRoute("GET", "/smol.css", serveFile("smol.css", "text/css")), | |
| 898 | - | router.NewRoute("GET", "/smol-v2.css", serveFile("smol-v2.css", "text/css")), | |
| 895 | + | router.NewRoute("GET", "/reset.css", serveFile("reset.css", "text/css")), | |
| 899 | 896 | router.NewRoute("GET", "/syntax.css", serveFile("syntax.css", "text/css")), | |
| 900 | 897 | router.NewRoute("GET", "/card.png", serveFile("card.png", "image/png")), | |
| 901 | 898 | router.NewRoute("GET", "/favicon-16x16.png", serveFile("favicon-16x16.png", "image/png")), |
+0
-2
pkg/apps/prose/html/base.layout.tmpl
#
| ... | ... | @@ -5,9 +5,7 @@ | |
| 5 | 5 | <meta charset='utf-8'> | |
| 6 | 6 | <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| 7 | 7 | <title>{{template "title" .}}</title> | |
| 8 | - | ||
| 9 | 8 | <meta name="keywords" content="blog, blogging, write, writing, hackers, developers, terminal" /> | |
| 10 | - | ||
| 11 | 9 | {{template "meta" .}} | |
| 12 | 10 | </head> | |
| 13 | 11 | <body {{template "attrs" .}}>{{template "body" .}}</body> |
+0
-56
pkg/apps/prose/html/blog-aside.partial.tmpl
#
| ... | ... | @@ -1,56 +0,0 @@ | |
| 1 | - | {{define "blog-aside"}} | |
| 2 | - | <main class="flex"> | |
| 3 | - | <section class="flex-1 mr"> | |
| 4 | - | <div> | |
| 5 | - | <h1 class="text-2xl font-bold mt-2">{{.Header.Title}}</h1> | |
| 6 | - | {{if .Header.Bio}}<span>{{.Header.Bio}}</span>{{end}} | |
| 7 | - | </div> | |
| 8 | - | ||
| 9 | - | <div id="readme"> | |
| 10 | - | {{if .Readme.HasText}} | |
| 11 | - | <section class="md"> | |
| 12 | - | {{.Readme.Contents}} | |
| 13 | - | </section> | |
| 14 | - | {{end}} | |
| 15 | - | <ul> | |
| 16 | - | {{range .Header.Nav}} | |
| 17 | - | <li><a href="{{.URL}}" class="text-lg">{{.Text}}</a></li> | |
| 18 | - | {{end}} | |
| 19 | - | <li><a href="{{.RSSURL}}" class="text-lg">rss</a></li> | |
| 20 | - | </ul> | |
| 21 | - | <hr /> | |
| 22 | - | </div> | |
| 23 | - | ||
| 24 | - | {{if .HasFilter}} | |
| 25 | - | <a href="/">clear filters</a> | |
| 26 | - | {{end}} | |
| 27 | - | ||
| 28 | - | <div class="posts group mt-2"> | |
| 29 | - | {{range .Posts}} | |
| 30 | - | <article> | |
| 31 | - | <div class="flex items-center"> | |
| 32 | - | <time datetime="{{.PublishAtISO}}" class="text-sm post-date">{{.PublishAt}}</time> | |
| 33 | - | <span class="text-md flex-1 m-0 transform-none"><a href="{{.URL}}">{{.Title}}</a></span> | |
| 34 | - | </div> | |
| 35 | - | </article> | |
| 36 | - | {{end}} | |
| 37 | - | </div> | |
| 38 | - | </section> | |
| 39 | - | ||
| 40 | - | <aside> | |
| 41 | - | {{if .Readme.HasText}} | |
| 42 | - | <section class="md"> | |
| 43 | - | {{.Readme.Contents}} | |
| 44 | - | </section> | |
| 45 | - | {{end}} | |
| 46 | - | <nav> | |
| 47 | - | <ul> | |
| 48 | - | {{range .Header.Nav}} | |
| 49 | - | <li><a href="{{.URL}}" class="text-md transform-none">{{.Text}}</a></li> | |
| 50 | - | {{end}} | |
| 51 | - | <li><a href="{{.RSSURL}}" class="text-md transform-none">rss</a></li> | |
| 52 | - | </ul> | |
| 53 | - | </nav> | |
| 54 | - | </aside> | |
| 55 | - | </main> | |
| 56 | - | {{end}} |
+22
-14
pkg/apps/prose/html/blog-default.partial.tmpl
#
| ... | ... | @@ -1,18 +1,23 @@ | |
| 1 | 1 | {{define "blog-default"}} | |
| 2 | - | <header class="text-center"> | |
| 3 | - | <h1 class="text-2xl font-bold mt-2">{{.Header.Title}}</h1> | |
| 4 | - | {{if .Header.Bio}}<span>{{.Header.Bio}}</span>{{end}} | |
| 2 | + | <header> | |
| 3 | + | <h1>{{.Header.Title}}</h1> | |
| 5 | 4 | <nav> | |
| 5 | + | {{if .Header.Bio}} | |
| 6 | + | <span>{{.Header.Bio}}</span> | |
| 7 | + | <br /> | |
| 8 | + | {{end}} | |
| 6 | 9 | {{range .Header.Nav}} | |
| 7 | - | <a href="{{.URL}}" class="text-lg transform-none">{{.Text}}</a> | | |
| 10 | + | <a href="{{.URL}}">{{.Text}}</a> | |
| 8 | 11 | {{end}} | |
| 9 | - | <a href="{{.RSSURL}}" class="text-lg transform-none">rss</a> | |
| 12 | + | <a href="{{.RSSURL}}">rss</a> | |
| 10 | 13 | </nav> | |
| 14 | + | ||
| 11 | 15 | <hr /> | |
| 12 | 16 | </header> | |
| 17 | + | ||
| 13 | 18 | <main> | |
| 14 | 19 | {{if .Readme.HasText}} | |
| 15 | - | <section> | |
| 20 | + | <section id="readme"> | |
| 16 | 21 | <article class="md"> | |
| 17 | 22 | {{.Readme.Contents}} | |
| 18 | 23 | </article> |
| ... | ... | @@ -20,18 +25,21 @@ | |
| 20 | 25 | </section> | |
| 21 | 26 | {{end}} | |
| 22 | 27 | ||
| 23 | - | <section class="posts group mt-2"> | |
| 28 | + | <section id="posts"> | |
| 24 | 29 | {{if .HasFilter}} | |
| 25 | - | <a href={{.URL}}>clear filters</a> | |
| 30 | + | <a href="{{.URL}}">clear filters</a> | |
| 26 | 31 | {{end}} | |
| 32 | + | ||
| 33 | + | <ul role="list"> | |
| 27 | 34 | {{range .Posts}} | |
| 28 | - | <article> | |
| 29 | - | <div class="flex items-center"> | |
| 30 | - | <time datetime="{{.PublishAtISO}}" class="text-sm post-date">{{.PublishAt}}</time> | |
| 31 | - | <span class="text-md flex-1 m-0 transform-none"><a href="{{.URL}}">{{.Title}}</a></span> | |
| 32 | - | </div> | |
| 33 | - | </article> | |
| 35 | + | <li> | |
| 36 | + | <article class="post"> | |
| 37 | + | <time datetime="{{.PublishAtISO}}">{{.PublishAt}}</time> | |
| 38 | + | <a href="{{.URL}}">{{.Title}}</a> | |
| 39 | + | </article> | |
| 40 | + | </li> | |
| 34 | 41 | {{end}} | |
| 42 | + | </ul> | |
| 35 | 43 | </section> | |
| 36 | 44 | </main> | |
| 37 | 45 | {{end}} |
+42
-53
pkg/apps/prose/html/blog.page.tmpl
#
| ... | ... | @@ -3,61 +3,50 @@ | |
| 3 | 3 | {{define "title"}}{{.PageTitle}}{{end}} | |
| 4 | 4 | ||
| 5 | 5 | {{define "meta"}} | |
| 6 | - | {{if .Header.Favicon}} | |
| 7 | - | <link rel="icon" href="{{.Header.Favicon}}"> | |
| 8 | - | {{else}} | |
| 9 | - | <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> | |
| 6 | + | {{if .Header.Favicon}} | |
| 7 | + | <link rel="icon" href="{{.Header.Favicon}}"> | |
| 8 | + | {{else}} | |
| 9 | + | <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> | |
| 10 | + | {{end}} | |
| 11 | + | ||
| 12 | + | <meta name="description" content="{{if .Header.Bio}}{{.Header.Bio}}{{else}}{{.Header.Title}}{{end}}" /> | |
| 13 | + | <meta property="og:type" content="website"> | |
| 14 | + | <meta property="og:site_name" content="{{.Site.Domain}}"> | |
| 15 | + | <meta property="og:url" content="{{.URL}}"> | |
| 16 | + | <meta property="og:title" content="{{.Header.Title}}"> | |
| 17 | + | {{if .Header.Bio}}<meta property="og:description" content="{{.Header.Bio}}">{{end}} | |
| 18 | + | ||
| 19 | + | {{if .Header.Image}} | |
| 20 | + | <meta itemprop="image" content="{{.Header.Image}}" /> | |
| 21 | + | <meta property="og:image" content="{{.Header.Image}}" /> | |
| 22 | + | <meta name="twitter:image" content="{{.Header.Image}}" /> | |
| 23 | + | {{else}} | |
| 24 | + | <meta property="og:image:width" content="300" /> | |
| 25 | + | <meta property="og:image:height" content="300" /> | |
| 26 | + | <meta itemprop="image" content="https://{{.Site.Domain}}/card.png" /> | |
| 27 | + | <meta property="og:image" content="https://{{.Site.Domain}}/card.png" /> | |
| 28 | + | <meta name="twitter:image" content="https://{{.Site.Domain}}/card.png" /> | |
| 29 | + | {{end}} | |
| 30 | + | ||
| 31 | + | {{if .Header.ImageCard}} | |
| 32 | + | <meta property="twitter:card" content="{{.Header.ImageCard}}"> | |
| 33 | + | {{else}} | |
| 34 | + | <meta property="twitter:card" content="summary"> | |
| 35 | + | {{end}} | |
| 36 | + | <meta property="twitter:url" content="{{.URL}}"> | |
| 37 | + | <meta property="twitter:title" content="{{.Header.Title}}"> | |
| 38 | + | {{if .Header.Bio}}<meta property="twitter:description" content="{{.Header.Bio}}">{{end}} | |
| 39 | + | ||
| 40 | + | <link rel="alternate" href="{{.RSSURL}}" type="application/rss+xml" title="RSS feed for {{.Header.Title}}" /> | |
| 41 | + | ||
| 42 | + | <link rel="stylesheet" href="/reset.css" /> | |
| 43 | + | <link rel="stylesheet" href="/syntax.css" /> | |
| 44 | + | {{if .HasCSS}}<link rel="stylesheet" href="{{.CssURL}}" />{{end}} | |
| 10 | 45 | {{end}} | |
| 11 | 46 | ||
| 12 | - | <meta name="description" content="{{if .Header.Bio}}{{.Header.Bio}}{{else}}{{.Header.Title}}{{end}}" /> | |
| 13 | - | ||
| 14 | - | <meta property="og:type" content="website"> | |
| 15 | - | <meta property="og:site_name" content="{{.Site.Domain}}"> | |
| 16 | - | <meta property="og:url" content="{{.URL}}"> | |
| 17 | - | <meta property="og:title" content="{{.Header.Title}}"> | |
| 18 | - | {{if .Header.Bio}}<meta property="og:description" content="{{.Header.Bio}}">{{end}} | |
| 19 | - | ||
| 20 | - | {{if .Header.Image}} | |
| 21 | - | <meta itemprop="image" content="{{.Header.Image}}" /> | |
| 22 | - | <meta property="og:image" content="{{.Header.Image}}" /> | |
| 23 | - | ||
| 24 | - | <meta name="twitter:image" content="{{.Header.Image}}" /> | |
| 25 | - | {{else}} | |
| 26 | - | <meta property="og:image:width" content="300" /> | |
| 27 | - | <meta property="og:image:height" content="300" /> | |
| 28 | - | <meta itemprop="image" content="https://{{.Site.Domain}}/card.png" /> | |
| 29 | - | <meta property="og:image" content="https://{{.Site.Domain}}/card.png" /> | |
| 30 | - | ||
| 31 | - | <meta name="twitter:image" content="https://{{.Site.Domain}}/card.png" /> | |
| 32 | - | {{end}} | |
| 33 | - | ||
| 34 | - | {{if .Header.ImageCard}} | |
| 35 | - | <meta property="twitter:card" content="{{.Header.ImageCard}}"> | |
| 36 | - | {{else}} | |
| 37 | - | <meta property="twitter:card" content="summary"> | |
| 38 | - | {{end}} | |
| 39 | - | <meta property="twitter:url" content="{{.URL}}"> | |
| 40 | - | <meta property="twitter:title" content="{{.Header.Title}}"> | |
| 41 | - | {{if .Header.Bio}}<meta property="twitter:description" content="{{.Header.Bio}}">{{end}} | |
| 42 | - | ||
| 43 | - | <link rel="alternate" href="{{.RSSURL}}" type="application/rss+xml" title="RSS feed for {{.Header.Title}}" /> | |
| 44 | - | {{if .WithStyles}} | |
| 45 | - | <link rel="stylesheet" href="/smol.css" /> | |
| 46 | - | {{else}} | |
| 47 | - | {{end}} | |
| 48 | - | <link rel="stylesheet" href="/syntax.css" /> | |
| 49 | - | {{if .HasCSS}}<link rel="stylesheet" href="{{.CssURL}}" />{{end}} | |
| 50 | - | {{end}} | |
| 51 | - | ||
| 52 | - | {{define "attrs"}}id="blog" class="layout-{{.Header.Layout}}"{{end}} | |
| 47 | + | {{define "attrs"}}id="blog"{{end}} | |
| 53 | 48 | ||
| 54 | 49 | {{define "body"}} | |
| 55 | - | ||
| 56 | - | {{if eq .Header.Layout "aside"}} | |
| 57 | - | {{template "blog-aside" .}} | |
| 58 | - | {{else}} | |
| 59 | - | {{template "blog-default" .}} | |
| 60 | - | {{end}} | |
| 61 | - | ||
| 62 | - | {{template "footer" .}} | |
| 50 | + | {{template "blog-default" .}} | |
| 51 | + | {{template "footer" .}} | |
| 63 | 52 | {{end}} |
+72
-66
pkg/apps/prose/html/post.page.tmpl
#
| ... | ... | @@ -3,86 +3,92 @@ | |
| 3 | 3 | {{define "title"}}{{.PageTitle}}{{end}} | |
| 4 | 4 | ||
| 5 | 5 | {{define "meta"}} | |
| 6 | - | {{if .Favicon}} | |
| 7 | - | <link rel="icon" href="{{.Favicon}}"> | |
| 8 | - | {{else}} | |
| 9 | - | <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> | |
| 10 | - | {{end}} | |
| 11 | - | ||
| 12 | - | <meta name="description" content="{{.Description}}" /> | |
| 6 | + | {{if .Favicon}} | |
| 7 | + | <link rel="icon" href="{{.Favicon}}"> | |
| 8 | + | {{else}} | |
| 9 | + | <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> | |
| 10 | + | {{end}} | |
| 13 | 11 | ||
| 14 | - | <meta property="og:type" content="website"> | |
| 15 | - | <meta property="og:site_name" content="{{.Site.Domain}}"> | |
| 16 | - | <meta property="og:url" content="{{.URL}}"> | |
| 17 | - | <meta property="og:title" content="{{.Title}}"> | |
| 18 | - | {{if .Description}}<meta property="og:description" content="{{.Description}}">{{end}} | |
| 12 | + | <meta name="description" content="{{.Description}}" /> | |
| 19 | 13 | ||
| 20 | - | {{if .Image}} | |
| 21 | - | <meta itemprop="image" content="{{.Image}}" /> | |
| 22 | - | <meta property="og:image" content="{{.Image}}" /> | |
| 14 | + | <meta property="og:type" content="website"> | |
| 15 | + | <meta property="og:site_name" content="{{.Site.Domain}}"> | |
| 16 | + | <meta property="og:url" content="{{.URL}}"> | |
| 17 | + | <meta property="og:title" content="{{.Title}}"> | |
| 18 | + | {{if .Description}}<meta property="og:description" content="{{.Description}}">{{end}} | |
| 23 | 19 | ||
| 24 | - | <meta name="twitter:image" content="{{.Image}}" /> | |
| 25 | - | {{else}} | |
| 26 | - | <meta property="og:image:width" content="300" /> | |
| 27 | - | <meta property="og:image:height" content="300" /> | |
| 28 | - | <meta itemprop="image" content="https://{{.Site.Domain}}/card.png" /> | |
| 29 | - | <meta property="og:image" content="https://{{.Site.Domain}}/card.png" /> | |
| 30 | - | ||
| 31 | - | <meta name="twitter:image" content="https://{{.Site.Domain}}/card.png" /> | |
| 32 | - | {{end}} | |
| 20 | + | {{if .Image}} | |
| 21 | + | <meta itemprop="image" content="{{.Image}}" /> | |
| 22 | + | <meta property="og:image" content="{{.Image}}" /> | |
| 23 | + | <meta name="twitter:image" content="{{.Image}}" /> | |
| 24 | + | {{else}} | |
| 25 | + | <meta property="og:image:width" content="300" /> | |
| 26 | + | <meta property="og:image:height" content="300" /> | |
| 27 | + | <meta itemprop="image" content="https://{{.Site.Domain}}/card.png" /> | |
| 28 | + | <meta property="og:image" content="https://{{.Site.Domain}}/card.png" /> | |
| 29 | + | <meta name="twitter:image" content="https://{{.Site.Domain}}/card.png" /> | |
| 30 | + | {{end}} | |
| 33 | 31 | ||
| 34 | - | {{if .ImageCard}} | |
| 35 | - | <meta property="twitter:card" content="{{.ImageCard}}"> | |
| 36 | - | {{else}} | |
| 37 | - | <meta property="twitter:card" content="summary"> | |
| 38 | - | {{end}} | |
| 39 | - | <meta property="twitter:url" content="{{.URL}}"> | |
| 40 | - | <meta property="twitter:title" content="{{.Title}}"> | |
| 41 | - | {{if .Description}}<meta property="twitter:description" content="{{.Description}}">{{end}} | |
| 32 | + | {{if .ImageCard}} | |
| 33 | + | <meta property="twitter:card" content="{{.ImageCard}}"> | |
| 34 | + | {{else}} | |
| 35 | + | <meta property="twitter:card" content="summary"> | |
| 36 | + | {{end}} | |
| 37 | + | <meta property="twitter:url" content="{{.URL}}"> | |
| 38 | + | <meta property="twitter:title" content="{{.Title}}"> | |
| 39 | + | {{if .Description}}<meta property="twitter:description" content="{{.Description}}">{{end}} | |
| 42 | 40 | ||
| 43 | - | <link rel="stylesheet" href="/syntax.css" /> | |
| 44 | - | {{if .WithStyles}} | |
| 45 | - | <link rel="stylesheet" href="/smol.css" /> | |
| 46 | - | {{else}} | |
| 47 | - | {{end}} | |
| 48 | - | {{if .HasCSS}}<link rel="stylesheet" href="{{.CssURL}}" />{{end}} | |
| 41 | + | <link rel="stylesheet" href="/reset.css" /> | |
| 42 | + | <link rel="stylesheet" href="/syntax.css" /> | |
| 43 | + | {{if .HasCSS}}<link rel="stylesheet" href="{{.CssURL}}" />{{end}} | |
| 49 | 44 | {{end}} | |
| 50 | 45 | ||
| 51 | 46 | {{define "attrs"}}id="post" class="{{.Slug}}{{if .Unlisted}} post-draft{{end}}"{{end}} | |
| 52 | 47 | ||
| 53 | 48 | {{define "body"}} | |
| 54 | - | <header> | |
| 55 | - | <h1 class="text-2xl font-bold">{{.Title}}</h1> | |
| 56 | - | <p class="font-bold m-0"> | |
| 57 | - | <span id="publish-at"> | |
| 49 | + | <main> | |
| 50 | + | <article class="md"> | |
| 51 | + | <header> | |
| 52 | + | <h1>{{.Title}}</h1> | |
| 53 | + | <p> | |
| 58 | 54 | <time datetime="{{.PublishAtISO}}">{{.PublishAt}}</time> | |
| 59 | 55 | <span>·</span> | |
| 60 | - | </span> | |
| 61 | - | <a href="{{.BlogURL}}">{{.BlogName}}</a> | |
| 62 | - | </p> | |
| 63 | - | {{if .Description}}<blockquote>{{.Description}}</blockquote>{{end}} | |
| 64 | - | <hr /> | |
| 65 | - | </header> | |
| 66 | - | <main> | |
| 67 | - | <article class="md"> | |
| 68 | - | {{if .List}} | |
| 69 | - | {{template "list" .List}} | |
| 70 | - | {{else}} | |
| 71 | - | {{.Contents}} | |
| 72 | - | {{end}} | |
| 73 | - | ||
| 74 | - | <div class="tags mt-4"> | |
| 75 | - | {{range .Tags}} | |
| 76 | - | <code class="pill tag"><a href="{{$.BlogURL}}?tag={{.}}">#{{.}}</a></code> | |
| 56 | + | <a href="{{.BlogURL}}">{{.BlogName}}</a> | |
| 57 | + | {{if .Description}} | |
| 58 | + | <br /> | |
| 59 | + | <span>{{.Description}}</span> | |
| 77 | 60 | {{end}} | |
| 78 | - | </div> | |
| 61 | + | </p> | |
| 62 | + | ||
| 63 | + | <hr /> | |
| 64 | + | </header> | |
| 65 | + | ||
| 66 | + | {{if .List}} | |
| 67 | + | {{template "list" .List}} | |
| 68 | + | {{else}} | |
| 69 | + | {{.Contents}} | |
| 70 | + | {{end}} | |
| 79 | 71 | ||
| 80 | - | <div id="last-updated" class="text-sm"> | |
| 81 | - | last updated: <time datetime="{{.UpdatedAtISO}}">{{.UpdatedAt}}</time> | |
| 82 | - | </div> | |
| 72 | + | <footer> | |
| 73 | + | <hr /> | |
| 74 | + | {{if or .Tags .UpdatedAt}} | |
| 75 | + | <p> | |
| 76 | + | {{if .Tags}} | |
| 77 | + | {{range .Tags}} | |
| 78 | + | <a href="{{$.BlogURL}}?tag={{.}}">#{{.}}</a> | |
| 79 | + | {{end}} | |
| 80 | + | {{if .UpdatedAt}}<br />{{end}} | |
| 81 | + | {{end}} | |
| 82 | + | {{if .UpdatedAt}} | |
| 83 | + | <span>last updated: <time datetime="{{.UpdatedAtISO}}">{{.UpdatedAt}}</time></span> | |
| 84 | + | {{end}} | |
| 85 | + | </p> | |
| 86 | + | {{end}} | |
| 83 | 87 | ||
| 84 | - | <div id="post-footer">{{.Footer}}</div> | |
| 88 | + | {{if .Footer}}<div id="post-footer">{{.Footer}}</div>{{end}} | |
| 89 | + | </footer> | |
| 85 | 90 | </article> | |
| 86 | - | </main> | |
| 87 | - | {{template "footer" .}} | |
| 91 | + | </main> | |
| 92 | + | ||
| 93 | + | {{template "footer" .}} | |
| 88 | 94 | {{end}} |
+95
-0
pkg/apps/prose/public/reset.css
#
| ... | ... | @@ -0,0 +1,95 @@ | |
| 1 | + | *, *::before, *::after { | |
| 2 | + | box-sizing: border-box; | |
| 3 | + | } | |
| 4 | + | ||
| 5 | + | :is(h1, h2, h3, h4, h5, h6, p, blockquote, hr, ul, ol, pre) + * { | |
| 6 | + | margin-top: 1rem; | |
| 7 | + | } | |
| 8 | + | ||
| 9 | + | html { | |
| 10 | + | color-scheme: light dark; | |
| 11 | + | } | |
| 12 | + | ||
| 13 | + | @media (prefers-reduced-motion: no-preference) { | |
| 14 | + | html { | |
| 15 | + | interpolate-size: allow-keywords; | |
| 16 | + | } | |
| 17 | + | } | |
| 18 | + | ||
| 19 | + | body { | |
| 20 | + | font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; | |
| 21 | + | max-width: 70ch; | |
| 22 | + | margin-inline: auto; | |
| 23 | + | padding-inline: 1rem; | |
| 24 | + | line-height: 1.5; | |
| 25 | + | -webkit-font-smoothing: antialiased; | |
| 26 | + | } | |
| 27 | + | ||
| 28 | + | img, picture, video, canvas, svg { | |
| 29 | + | display: block; | |
| 30 | + | max-width: 100%; | |
| 31 | + | height: auto; | |
| 32 | + | } | |
| 33 | + | ||
| 34 | + | input, button, textarea, select { | |
| 35 | + | font: inherit; | |
| 36 | + | } | |
| 37 | + | ||
| 38 | + | code, kbd, samp, pre { | |
| 39 | + | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; | |
| 40 | + | font-size: 1em; | |
| 41 | + | } | |
| 42 | + | ||
| 43 | + | pre { | |
| 44 | + | overflow-x: auto; | |
| 45 | + | } | |
| 46 | + | ||
| 47 | + | table { | |
| 48 | + | border-collapse: collapse; | |
| 49 | + | border-spacing: 0; | |
| 50 | + | } | |
| 51 | + | ||
| 52 | + | hr { | |
| 53 | + | border: none; | |
| 54 | + | border-top: 1px solid currentColor; | |
| 55 | + | } | |
| 56 | + | ||
| 57 | + | p, h1, h2, h3, h4, h5, h6 { | |
| 58 | + | overflow-wrap: break-word; | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | p { | |
| 62 | + | text-wrap: pretty; | |
| 63 | + | } | |
| 64 | + | ||
| 65 | + | h1, h2, h3, h4, h5, h6 { | |
| 66 | + | text-wrap: balance; | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | blockquote { | |
| 70 | + | border-inline-start: 2px solid currentColor; | |
| 71 | + | padding-inline-start: 1ch; | |
| 72 | + | margin: 0; | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | [role="list"] { | |
| 76 | + | display: flex; | |
| 77 | + | flex-direction: column; | |
| 78 | + | gap: 0.5rem; | |
| 79 | + | list-style: none; | |
| 80 | + | padding: 0; | |
| 81 | + | } | |
| 82 | + | ||
| 83 | + | [role="list"] [role="list"] { | |
| 84 | + | margin-left: 1.3rem; | |
| 85 | + | } | |
| 86 | + | ||
| 87 | + | [role="listitem"] { | |
| 88 | + | display: flex; | |
| 89 | + | align-items: flex-start; | |
| 90 | + | gap: 5px; | |
| 91 | + | } | |
| 92 | + | ||
| 93 | + | [role="listitem"]:has(pre, img, blockquote) { | |
| 94 | + | align-items: center; | |
| 95 | + | } |