diff options
| author | Christine Dodrill <me@christine.website> | 2019-05-21 21:47:09 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-05-21 21:47:09 -0400 |
| commit | d64c666255665c5e03812c47e70d6edb46432510 (patch) | |
| tree | 1dd44e77f7d57a5a52ccfa0fe96fc073cb3da2fe | |
| parent | a275fc754b4c82a81ba06f0f3cbddb39946db1ac (diff) | |
| download | xesite-d64c666255665c5e03812c47e70d6edb46432510.tar.xz xesite-d64c666255665c5e03812c47e70d6edb46432510.zip | |
add talks support (#40)
* add talks support
* gosimplify
| -rw-r--r-- | Dockerfile | 5 | ||||
| -rw-r--r-- | cmd/site/html.go | 46 | ||||
| -rw-r--r-- | cmd/site/main.go | 20 | ||||
| -rw-r--r-- | internal/blog/blog.go | 14 | ||||
| -rw-r--r-- | internal/blog/blog_test.go | 38 | ||||
| -rwxr-xr-x | static/js/sw.js | 10 | ||||
| -rw-r--r-- | static/talks/irc-why-it-failed.pdf | bin | 0 -> 807223 bytes | |||
| -rw-r--r-- | static/talks/thinking-different.pdf | bin | 0 -> 1096651 bytes | |||
| -rw-r--r-- | talks/irc-why-it-failed-2018-05-17.markdown | 13 | ||||
| -rw-r--r-- | talks/thinking-different-2018-11-03.markdown | 11 | ||||
| -rw-r--r-- | templates/base.html | 2 | ||||
| -rw-r--r-- | templates/talkindex.html | 20 | ||||
| -rw-r--r-- | templates/talkpost.html | 103 |
13 files changed, 267 insertions, 15 deletions
@@ -2,8 +2,8 @@ FROM xena/go:1.12.1 AS build ENV GOPROXY https://cache.greedo.xeserv.us COPY . /site WORKDIR /site -RUN CGO_ENABLED=0 go test ./... -RUN CGO_ENABLED=0 GOBIN=/root go install ./cmd/site +RUN CGO_ENABLED=0 go test -v ./... +RUN CGO_ENABLED=0 GOBIN=/root go install -v ./cmd/site FROM xena/alpine EXPOSE 5000 @@ -13,6 +13,7 @@ COPY --from=build /root/site . COPY ./static /site/static COPY ./templates /site/templates COPY ./blog /site/blog +COPY ./talks /site/talks COPY ./css /site/css COPY ./app /app COPY ./app.json . diff --git a/cmd/site/html.go b/cmd/site/html.go index 9f208af..b3fa484 100644 --- a/cmd/site/html.go +++ b/cmd/site/html.go @@ -66,9 +66,53 @@ func (s *Site) renderTemplatePage(templateFname string, data interface{}) http.H var postView = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "posts_viewed", - Help: "The number of views per post", + Help: "The number of views per post or talk", }, []string{"base"}) +func (s *Site) showTalk(w http.ResponseWriter, r *http.Request) { + if r.RequestURI == "/talks/" { + http.Redirect(w, r, "/talks", http.StatusSeeOther) + return + } + + cmp := r.URL.Path[1:] + var p blog.Post + var found bool + for _, pst := range s.Talks { + if pst.Link == cmp { + p = pst + found = true + } + } + + if !found { + w.WriteHeader(http.StatusNotFound) + s.renderTemplatePage("error.html", "no such post found: "+r.RequestURI).ServeHTTP(w, r) + return + } + + const dateFormat = `2006-01-02` + h := s.renderTemplatePage("talkpost.html", struct { + Title string + Link string + BodyHTML template.HTML + Date string + SlidesLink string + }{ + Title: p.Title, + Link: p.Link, + BodyHTML: p.BodyHTML, + Date: p.Date.Format(dateFormat), + SlidesLink: p.SlidesLink, + }) + + if h == nil { + panic("how did we get here?") + } + + h.ServeHTTP(w, r) +} + func (s *Site) showPost(w http.ResponseWriter, r *http.Request) { if r.RequestURI == "/blog/" { http.Redirect(w, r, "/blog", http.StatusSeeOther) diff --git a/cmd/site/main.go b/cmd/site/main.go index b562017..055320e 100644 --- a/cmd/site/main.go +++ b/cmd/site/main.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "net/http" "os" + "sort" "time" "christine.website/internal/blog" @@ -54,6 +55,7 @@ func main() { // Site is the parent object for https://christine.website's backend. type Site struct { Posts blog.Posts + Talks blog.Posts Resume template.HTML rssFeed *feeds.Feed @@ -134,12 +136,24 @@ func Build() (*Site, error) { xffmw: xffmw, } - posts, err := blog.LoadPosts("./blog/") + posts, err := blog.LoadPosts("./blog/", "blog") if err != nil { return nil, err } s.Posts = posts + talks, err := blog.LoadPosts("./talks", "talks") + if err != nil { + return nil, err + } + s.Talks = talks + + var everything blog.Posts + everything = append(everything, posts...) + everything = append(everything, talks...) + + sort.Sort(sort.Reverse(everything)) + resumeData, err := ioutil.ReadFile("./static/resume/resume.md") if err != nil { return nil, err @@ -147,7 +161,7 @@ func Build() (*Site, error) { s.Resume = template.HTML(blackfriday.Run(resumeData)) - for _, item := range s.Posts { + for _, item := range everything { s.rssFeed.Items = append(s.rssFeed.Items, &feeds.Item{ Title: item.Title, Link: &feeds.Link{Href: "https://christine.website/" + item.Link}, @@ -184,11 +198,13 @@ func Build() (*Site, error) { s.mux.Handle("/metrics", promhttp.Handler()) s.mux.Handle("/resume", middleware.Metrics("resume", s.renderTemplatePage("resume.html", s.Resume))) s.mux.Handle("/blog", middleware.Metrics("blog", s.renderTemplatePage("blogindex.html", s.Posts))) + s.mux.Handle("/talks", middleware.Metrics("talks", s.renderTemplatePage("talkindex.html", s.Talks))) s.mux.Handle("/contact", middleware.Metrics("contact", s.renderTemplatePage("contact.html", nil))) s.mux.Handle("/blog.rss", middleware.Metrics("blog.rss", http.HandlerFunc(s.createFeed))) s.mux.Handle("/blog.atom", middleware.Metrics("blog.atom", http.HandlerFunc(s.createAtom))) s.mux.Handle("/blog.json", middleware.Metrics("blog.json", http.HandlerFunc(s.createJSONFeed))) s.mux.Handle("/blog/", middleware.Metrics("blogpost", http.HandlerFunc(s.showPost))) + s.mux.Handle("/talks/", middleware.Metrics("talks", http.HandlerFunc(s.showTalk))) s.mux.Handle("/css/", http.FileServer(http.Dir("."))) s.mux.Handle("/static/", http.FileServer(http.Dir("."))) s.mux.HandleFunc("/sw.js", func(w http.ResponseWriter, r *http.Request) { diff --git a/internal/blog/blog.go b/internal/blog/blog.go index a73f27b..eac5d64 100644 --- a/internal/blog/blog.go +++ b/internal/blog/blog.go @@ -20,6 +20,7 @@ type Post struct { Summary string `json:"summary,omitifempty"` Body string `json:"-"` BodyHTML template.HTML `json:"body"` + SlidesLink string `json:"slides_link"` Date time.Time DateString string `json:"date"` } @@ -37,10 +38,11 @@ func (p Posts) Less(i, j int) bool { func (p Posts) Swap(i, j int) { p[i], p[j] = p[j], p[i] } // LoadPosts loads posts for a given directory. -func LoadPosts(path string) (Posts, error) { +func LoadPosts(path string, prepend string) (Posts, error) { type postFM struct { - Title string - Date string + Title string + Date string + SlidesLink string `yaml:"slides_link"` } var result Posts @@ -78,13 +80,17 @@ func LoadPosts(path string) (Posts, error) { return err } + fname := filepath.Base(path) + fname = strings.TrimSuffix(fname, filepath.Ext(fname)) + p := Post{ Title: fm.Title, Date: date, DateString: fm.Date, - Link: strings.Split(path, ".")[0], + Link: filepath.Join(prepend, fname), Body: string(remaining), BodyHTML: template.HTML(output), + SlidesLink: fm.SlidesLink, } result = append(result, p) diff --git a/internal/blog/blog_test.go b/internal/blog/blog_test.go index b073880..8a446cd 100644 --- a/internal/blog/blog_test.go +++ b/internal/blog/blog_test.go @@ -5,8 +5,44 @@ import ( ) func TestLoadPosts(t *testing.T) { - _, err := LoadPosts("../../blog") + posts, err := LoadPosts("../../blog", "blog") if err != nil { t.Fatal(err) } + + for _, post := range posts { + t.Run(post.Link, post.test) + } +} + +func TestLoadTalks(t *testing.T) { + talks, err := LoadPosts("../../talks", "talks") + if err != nil { + t.Fatal(err) + } + + for _, talk := range talks { + t.Run(talk.Link, talk.test) + if talk.SlidesLink == "" { + t.Errorf("talk %s (%s) doesn't have a slides link", talk.Title, talk.DateString) + } + } +} + +func (p Post) test(t *testing.T) { + if p.Title == "" { + t.Error("no post title") + } + + if p.DateString == "" { + t.Error("no date") + } + + if p.Link == "" { + t.Error("no link") + } + + if p.Body == "" { + t.Error("no body") + } } diff --git a/static/js/sw.js b/static/js/sw.js index f258902..deaa947 100755 --- a/static/js/sw.js +++ b/static/js/sw.js @@ -5,11 +5,13 @@ self.addEventListener('install', function(event) { event.waitUntil(preLoad());
});
+const cacheName = "cache-2019-05-21";
+
var preLoad = function(){
console.log('[PWA Builder] Install Event processing');
- return caches.open('offline').then(function(cache) {
+ return caches.open(cacheName).then(function(cache) {
console.log('[PWA Builder] Cached index and offline page during Install');
- return cache.addAll(['/blog/', '/blog', '/', '/contact', '/resume']);
+ return cache.addAll(['/blog/', '/blog', '/', '/contact', '/resume', '/talks']);
});
};
@@ -37,7 +39,7 @@ var checkResponse = function(request){ };
var addToCache = function(request){
- return caches.open('offline').then(function (cache) {
+ return caches.open(cacheName).then(function (cache) {
return fetch(request).then(function (response) {
console.log('[PWA Builder] add page to offline: ' + response.url);
return cache.put(request, response);
@@ -46,7 +48,7 @@ var addToCache = function(request){ };
var returnFromCache = function(request){
- return caches.open('offline').then(function (cache) {
+ return caches.open(cacheName).then(function (cache) {
return cache.match(request).then(function (matching) {
if(!matching || matching.status == 404) {
return cache.match('offline.html');
diff --git a/static/talks/irc-why-it-failed.pdf b/static/talks/irc-why-it-failed.pdf Binary files differnew file mode 100644 index 0000000..6d81031 --- /dev/null +++ b/static/talks/irc-why-it-failed.pdf diff --git a/static/talks/thinking-different.pdf b/static/talks/thinking-different.pdf Binary files differnew file mode 100644 index 0000000..fd225ee --- /dev/null +++ b/static/talks/thinking-different.pdf diff --git a/talks/irc-why-it-failed-2018-05-17.markdown b/talks/irc-why-it-failed-2018-05-17.markdown new file mode 100644 index 0000000..b9dcc80 --- /dev/null +++ b/talks/irc-why-it-failed-2018-05-17.markdown @@ -0,0 +1,13 @@ +--- +title: "IRC: Why it Failed" +date: 2018-05-17 +slides_link: /static/talks/irc-why-it-failed.pdf +--- + +# IRC: Why it Failed + +A brief discussion of the IRC protocol and why it has failed in today's internet. + +Originally presented at the Pony Developers panel at Everfree Northwest, 2018. + +Please check out [pony.dev](https://pony.dev) for more information. diff --git a/talks/thinking-different-2018-11-03.markdown b/talks/thinking-different-2018-11-03.markdown new file mode 100644 index 0000000..29ccd5e --- /dev/null +++ b/talks/thinking-different-2018-11-03.markdown @@ -0,0 +1,11 @@ +--- +title: "Thinking Different" +date: 2018-11-03 +slides_link: /static/talks/thinking-different.pdf +--- + +# Thinking Different + +A look over [ilo Kesi](https://github.com/Xe/x/tree/master/discord/ilo-kesi), a chatbot of mine that parses commands from the grammar of [Toki Pona](http://tokipona.org). + +Originally presented privately at an internal work get-together for Heroku. diff --git a/templates/base.html b/templates/base.html index 1cbaff3..3fdc591 100644 --- a/templates/base.html +++ b/templates/base.html @@ -59,7 +59,7 @@ {{ template "scripts" . }} <div class="container"> <header> - <p><a href="/">Christine Dodrill</a> - <a href="/blog">Blog</a> - <a href="/contact">Contact</a> - <a href="/resume">Resume</a> | <a target="_blank" rel="noopener noreferrer" href="https://graphviz.christine.website">GraphViz</a> - <a target="_blank" rel="noopener noreferrer" href="https://when-then-zen.christine.website/">When Then Zen</a></p> + <p><a href="/">Christine Dodrill</a> - <a href="/blog">Blog</a> - <a href="/contact">Contact</a> - <a href="/resume">Resume</a> - <a href="/talks">Talks</a> | <a target="_blank" rel="noopener noreferrer" href="https://graphviz.christine.website">GraphViz</a> - <a target="_blank" rel="noopener noreferrer" href="https://when-then-zen.christine.website/">When Then Zen</a></p> </header> <div class="snowframe"> diff --git a/templates/talkindex.html b/templates/talkindex.html new file mode 100644 index 0000000..9fad850 --- /dev/null +++ b/templates/talkindex.html @@ -0,0 +1,20 @@ +{{ define "title" }} +<title>Blog - Christine Dodrill</title> +{{ end }} + +{{ define "content" }} +<h1>Talks</h1> + +<p>Here is a link to all of the talks I have done at conferences. Each of these will have links to the slides (PDF) as well as some brief information about them.</p> + +<p>If you have a compatible reader, be sure to check out my <a href="/blog.rss">RSS Feed</a> for automatic updates. Also check out the <a href="/blog.json">JSONFeed</a>.</p> + +<p> + <ul> + {{ range . }} + <li>{{ .DateString }} - <a href="{{ .Link }}">{{ .Title }}</a></li> + {{ end }} + </ul> +</p> + +{{ end }} diff --git a/templates/talkpost.html b/templates/talkpost.html new file mode 100644 index 0000000..94ddc0f --- /dev/null +++ b/templates/talkpost.html @@ -0,0 +1,103 @@ +{{ define "title" }} +<title>{{ .Title }} - Christine Dodrill</title> + +<!-- Twitter --> +<meta name="twitter:card" content="summary" /> +<meta name="twitter:site" content="@theprincessxena" /> +<meta name="twitter:title" content="{{ .Title }}" /> +<meta name="twitter:description" content="Posted on {{ .Date }}" /> + +<!-- Facebook --> +<meta property="og:type" content="website" /> +<meta property="og:title" content="{{ .Title }}" /> +<meta property="og:site_name" content="Talk by Christine Dodrill" /> + +<!-- Description --> +<meta name="description" content="{{ .Title }} - Talk by Christine Dodrill" /> +<meta name="author" content="Christine Dodrill"> + +<link rel="canonical" href="https://christine.website/{{ .Link }}"> + +<script type="application/ld+json"> + { + "@context": "http://schema.org", + "@type": "Article", + "headline": "{{ .Title }}", + "image": "https://christine.website/static/img/avatar.png", + "url": "https://christine.website/{{ .Link }}", + "datePublished": "{{ .Date }}", + "mainEntityOfPage": { + "@type": "WebPage", + "@id": "https://christine.website/{{ .Link }}" + }, + "author": { + "@type": "Person", + "name": "Christine Dodrill" + }, + "publisher": { + "@type": "Person", + "name": "Christine Dodrill" + } + } +</script> +{{ end }} + +{{ define "content" }} +{{ .BodyHTML }} + +<a href="{{ .SlidesLink }}">Link to the slides</a> + +<hr /> + +<!-- The button that should be clicked. --> +<button onclick="share_on_mastodon()">Share on Mastodon</button> +<script> + +// The actual function. Set this as an onclick function for your "Share on Mastodon" button +function share_on_mastodon() { + // Prefill the form with the user's previously-specified Mastodon instance, if applicable + var default_url = localStorage['mastodon_instance']; + + // If there is no cached instance/domain, then insert a "https://" with no domain at the start of the prompt. + if (!default_url) + default_url = "https://"; + + var instance = prompt("Enter your instance's address: (ex: https://linuxrocks.online)", default_url); + if (instance) { + // Handle URL formats + if ( !instance.startsWith("https://") && !instance.startsWith("http://") ) + instance = "https://" + instance; + + // Get the current page's URL + var url = window.location.href; + + // Get the page title from the og:title meta tag, if it exists. + var title = document.querySelectorAll('meta[property="og:title"]')[0].getAttribute("content"); + + // Otherwise, use the <title> tag as the title + if (!title) var title = document.getElementsByTagName("title")[0].innerHTML; + + // Handle slash + if ( !instance.endsWith("/") ) + instance = instance + "/"; + + // Cache the instance/domain for future requests + localStorage['mastodon_instance'] = instance; + + // Hashtags + var hashtags = "#blogpost"; + + // Tagging users, such as offical accounts or the author of the post + var author = "@cadey@mst3k.interlinked.me"; + + // Create the Share URL + // https://someinstance.tld/share?text=URL%20encoded%20text + mastodon_url = instance + "share?text=" + encodeURIComponent(title + "\n\n" + url + "\n\n" + hashtags + " " + author); + + // Open a new window at the share location + window.open(mastodon_url, '_blank'); + } +} +</script> + +{{ end }} |
