704923fe4b3a9fb0e23f94db763a9fe17d4601d6 — Andrew Zah 3 months ago 7e8722a
change highlights to inline-block, add post 18
M config.toml => config.toml +1 -3
@@ 3,7 3,7 @@ compile_sass = true
  
  # RSS
- title = "Andrew Zah"
+ title = "AZ"
  description = "Sometimes relevant thoughts by Andrew"
  default_language = "en"
  rss_limit = 20


@@ 19,6 19,4 @@ ]
  
  [extra]
- languagecode = "en"
- subtitle = "Foremost expert on Smash Bros. Melee"
  author = { name = "Andrew Zah" }

M content/posts/008_programming_korean/index.md => content/posts/008_programming_korean/index.md +6 -4
@@ 13,6 13,10 @@ summary = "Korean has similarities with functional programming languages."
  show_summary = true
  
+ footnotes = [
+   "Note that `갔` changed to `간`. `갔` is 가다 (to go) + `~ㅆ` (past tense). But the past tense nominalization form uses `~ㄴ (것)`. Instead of 것 (thing) we swapped it for another noun 여자 (woman)."
+ ]
+ 
  references = [
    ["German for Programmers", "https://wickedchicken.github.io/post/german-for-programmers/"],
    ["Hangeul Grid Order ", "https://www.howtostudykorean.com/unit0/unit0lesson1/"],


@@ 211,17 215,15 @@ So, let's take 'the girl walked to school'. In English and Korean this is straightfoward enough:
  
  <p>
-   {{hlw(c="green", t="여자는")}} {{hll(c="pink",t="학교")}}{{hlrw(c="purple",t="로")}}{{hlw(c="blue",t="걸어")}} {{hlw(c="blue",t="갔어요")}} — {{hlw(c="green",t="The girl")}} {{hlw(c="blue",t="walked")}}{{hlw(c="purple",t="to")}} {{hlrw(c="pink",t="school")}}
+   {{hlw(c="green", t="여자는")}} {{hll(c="pink",t="학교")}}{{hlr(c="purple",t="로")}} {{hlw(c="blue",t="걸어")}} {{hlw(c="blue",t="갔어요")}} — {{hlw(c="green",t="The girl")}} {{hlw(c="blue",t="walked")}} {{hlw(c="purple",t="to")}} {{hlrw(c="pink",t="school")}}
  </p>
  
  But what if you wanted to talk *about* that person? You could say "the girl *who* walked to school". In English, this these are known as relative causes. They can begin with `who`, `which`, `that`, `where`, etc, *following* the noun. Korean uses the `~는 것` nominalizer *before* the noun, which leads to:
  
  <p>
-   {{hll(c="pink", t="학교")}}{{hlrw(c="purple", t="로")}} {{hlw(c="blue",t="걸어")}} {{hlw(c="orange",t="간")}} {{hlrw(c="green",t="여자")}}!
+   {{hll(c="pink", t="학교")}}{{hlrw(c="purple", t="로")}} {{hlw(c="blue",t="걸어")}} {{hlw(c="orange",t="간")}} {{hlrw(c="green",t="여자")}}!{{footnote(num=0)}}
  </p>
  
- Note that `갔` changed to `간`. `갔` is 가다 (to go) + `~ㅆ` (past tense). But the past tense nominalization form uses `~ㄴ (것)`. Instead of 것 (thing) we swapped it for another noun 여자 (woman).
- 
  Not that one would only say "the girl who walked to school" by itself, but we can now use the entire construct as a noun in other sentences:
  
  <p>

A content/posts/018_zola_caddy_automatic_deploy/index.md => content/posts/018_zola_caddy_automatic_deploy/index.md +297 -0
@@ 0,0 1,297 @@
+ +++
+ title = "Automatically deploy your blog via Git with Caddy and Docker"
+ slug = "automatically-deploy-your-blog-via-git-caddy-docker"
+ date = 2019-06-02
+ template = "post.html"
+ draft = false
+ 
+ [taxonomies]
+ tags = ["zola", "caddy", "docker"]
+ categories = ["programming"]
+ 
+ [extra]
+ keywords = "automatic automatically deploy caddy docker zola gutenberg static site generation blog"
+ summary = "Using Caddy, Docker, and Zola, one can easily deploy updates to their blog with a git push."
+ 
+ footnotes = [
+   "Philipp Offerman's fantastic blog, Writing an OS in Rust, uses Zola.",
+   "Initially I made the mistake of including binary data in my site's repo. This blew up my docker alpine image from ~2mb to ~35mb before I realized. Whoops.",
+   "I made this mistake when I ran the the Docker image for the first time. Hitting `ctrl-c` wouldn't kill it, I had to run `docker-compose down`... but I ran it too late. I had to wait 24 hours to deploy HTTPS for my site after that."
+ ]
+ +++
+ 
+ Over the years, I've slowly and incrementally optimized my blog. Originally I used an entire rails setup with postgres, because that was the first thing I really learned how to program. Yet that's quite the overkill for a static blog... I don't even include comments anymore.
+ 
+ This is where [Zola][Zola] comes in, previously named *Gutenberg*. It's a static site generator written in Rust that uses [Tera][tera] for templating. It serves as a counterpart to [Hugo][hugo], written in Golang. Both have a similar featureset, so I chose Zola since I know Rust and can contribute if needed.
+ 
+ However basically [any static site generation system][buildit] can work, so long as you end up with files generated to your liking.
+ 
+ ## Zola
+ Feel free to skip this section if you already have your own static site generation system.
+ 
+ **One caveat**: Zola minifies sass by default but not javascript. I use a [Makefile][makefile] to minify the js files and bundle them.
+ 
+ #### Getting started
+ 
+ Zola has a [getting started][zola-started] guide. For inspiration, you can look at the [source code for this very blog][source] or [different sites using Zola][zola-examples].{{footnote(num=0)}}
+ 
+ #### My setup
+ This is what my site's directory looks like:
+ 
+ ```
+ .
+ ├── binary-data/
+ ├── Caddyfile
+ ├── config.toml
+ ├── content/
+ ├── docker-compose.yml
+ ├── Dockerfile
+ ├── LICENSE
+ ├── Makefile
+ ├── public/
+ ├── sass/
+ ├── static/
+ ├── syntaxes/
+ ├── templates/
+ └── themes/
+ ```
+ 
+ `binary-data` is where I store all the screenshots, pdfs, and other binary data I refer to my posts. For the actual posts I upload these to an amazon S3 bucket, but I keep these as a backup, *outside* of git.{{footnote(num=1)}}
+ 
+ `sass/` and `static/` are pretty easy: the former gets compiled to css, the latter gets copied directly to the `public/` directory during generation.
+ 
+ For code, `themes` contains the syntax highlighting theme, and `syntaxes` contains sublime syntax files I added because Zola doesn't support [slim][slim] syntax highlighting yet.
+ 
+ [slim]: http://slim-lang.com/
+ 
+ This leaves us `content`, the actual posts and pages, and `templates`, for how to render them. `templates` also contains `shortcodes/`, which function much like wordpress' shortcodes.
+ 
+ #### Templating
+ 
+ [These][templates] are all the templates I've made. Naturally it can get as complex as you want. I generally have one per page or page type, such as /projects or /posts.
+ 
+ At a minimum, you probably want a [base.html][base] to deal with the oh-so-fun SEO stuff, and a `macros.html` for "dynamically" rendering things. I use it for the navigation bar, footnotes, references, citations, and rendering links.
+ 
+ With child templates, you can use blocks to inject content back to the parent:
+ 
+ ```html
+ <!-- base.html -->
+ <head>
+   <!-- constants in base.html header -->
+   <meta charset="UTF-8">
+ 
+   <!-- set from child -->
+   <title>{% block title %}{% endblock title %}</title>
+   {% block head %}{% endblock head %}
+ </head>
+ ```
+ then in the child you define the block:
+ ```html
+ <!-- zola provides objects like page/section/config, see the docs -->
+ {% block title %}{{ page.title }} | {{ config.title }}{% endblock title %}
+ ```
+ 
+ Thrilling stuff.
+ 
+ If you look at my source it can appear a tad complex now, but I just slowly added things as they came up– like the page title, then custom SEO attributes, etc.
+ 
+ #### Macros
+ 
+ Tera's macro system is really useful. One of my use cases was to show the tags and categories below a post:
+ 
+ ```html
+ {% macro render_tags(tags) %}
+   <div class="tags">
+     Tags: 
+     {% for tag in tags %}
+       {% if loop.last %}
+         <a href="/tags/{{ tag | slugify }}/">{{ tag | title }}</a>
+       {% else %}
+         <a href="/tags/{{ tag | slugify }}/">{{ tag | title }}</a> | 
+       {% endif %}
+     {% endfor %}
+   </div>
+ {% endmacro render_tags %}
+ ```
+ Yes, I should probably clean them up a bit. They work good enough for now.
+ 
+ #### Shortcodes
+ Shortcodes are awesome. Two main things I use them for:
+ 
+ * footnotes, citations, references
+ * generating boilerplate for lity.js (a lightbox lib)
+ 
+ ```html
+ <!-- img.html -->
+ <a href="{{url}}" data-lity data-lity-desc="{{desc}}" alt="{{desc}}">
+   <img class="full" async-src="{{url}}"/>
+ </a>
+ {% if t %}
+   <p class="image-desc"> {{t}} </p>
+ {% endif %}
+ ```
+ ```html
+ <!-- footnote.html -->
+ <a id="footnote-cite-{{num}}" href="#footnote-{{num}}">({{num}})</a>
+ ```
+ 
+ My [Korean for Programmers][kp] post uses ~5 shortcodes to {{hl(t="highlight",c="red")}} words in different colors:
+ 
+ ```html
+ <!-- hlm.html -->
+ <!-- where t=text,c=css color class name-->
+ <span class="hl hl-middle hl-{{c}}">
+   {{t}}
+ </span>
+ ```
+ 
+ Okay, okay.. Time for the real stuff.
+ 
+ ## Static Assets Repo
+ Now that you have your static files, commit them to a new git repo. With Zola, I use `rsync` to move the output from `public/` to another directory–since `zola build` nukes it each time.
+ 
+ As stated earlier I keep binary files like images in a separate directory, and in the posts themselves I link to amazon s3. If you want to link to assets locally, you might need something like [Git LFS][lfs] from Github or or a different solution.
+ 
+ I keep my statically generated assets at [github.com/azah/personal-site-public][static-assets] because sourcehut doesn't support webhooks yet.
+ 
+ ## Caddy
+ 
+ [Caddy][caddy] is an awesome HTTP/2 web server. It handles SSL certs for you automatically via Lets Encrypt, and it has a `git` plugin which we'll be using. The git plugin clones or updates a repo for us, so we can now push content to a git repo and have it automatically update!
+ 
+ Let's create the Caddyfile:
+ 
+ **NOTE**!! Use a port (like :2015) for local testing instead of the actual domain! If you run Caddy with this caddyfile locally without the `-disable-acme-auth`, caddy will repeatedly try to authorize, quickly **ratelimiting you from Let's Encrypt**!{{footnote(num=2)}}
+ 
+ ```
+ # Caddyfile
+ andrewzah.com, andrei.kr {
+   gzip
+   cache {
+     default_max_age 10m
+   }
+ 
+   git {
+     hook /webhook {%SITE_WEBHOOK%}
+     repo https://github.com/azah/personal-site-public.git
+     branch master
+     clone_args --recurse-submodules
+     pull_args --recurse-submodules
+     interval 86400
+     hook_type github
+   }
+ 
+   root /www/public
+ }
+ ```
+ 
+ The `SITE_WEBHOOK` environment variable is set in `.env`.
+ 
+ Note that a webhook is optional. In fact, [all of the git directives here are optional][caddy-git] besides the repo path itself. By default the plugin clones to the root path, `/www/public` in this case.
+ 
+ I've set it to pull once per day as well as listen for requests on `/webhook`. Right now I use github webhooks as `sourcehut` doesn't seem to support webhooks yet.
+ 
+ If you're running multiple containerized services you can use caddy as a proxy as well. You can see the [source for andrewzah.com's docker script][andrewzahcom] as an example. I have an `http` docker service that proxies to my `website` service, which looks like the following:
+ 
+ ```
+ # services/http/Caddyfile
+ www.andrewzah.com, andrewzah.com, andrei.blue {
+   gzip
+   tls zah@andrewzah.com
+ 
+   log / stdout {combined}
+   errors stderr
+ 
+   proxy /webhook http://website:1111/webhook {
+     transparent
+   }
+ 
+   proxy / http://website:1111
+ }
+ 
+ ...
+ ```
+ 
+ ## Docker
+ 
+ Lastly, we'll run all of this inside a docker container, so we need a `Dockerfile`:
+ 
+ ```docker
+ FROM alpine:edge
+ LABEL caddy_version = "1.0.0" architecture="amd64"
+ 
+ # Caddy
+ RUN adduser -S caddy
+ 
+ ARG plugins=http.git,http.cache
+ ARG version=v1.0.0
+ 
+ RUN apk add --no-cache --virtual .build-caddy openssh-client tar curl \
+   && apk add --no-cache git \
+   && curl --silent --show-error --fail --location \
+   --header "Accept: application/tar+gzip, application/x-zip, application/octet-stream" -p \
+   "https://caddyserver.com/download/linux/amd64?version=${version}&plugins=${plugins}&license=personal&telemetry=off" \
+   | tar --no-same-owner -C /usr/bin -xz caddy \
+   && chmod 0755 /usr/bin/caddy \
+   && apk del --purge .build-caddy
+ 
+ RUN /usr/bin/caddy --plugins
+ RUN mkdir /www \
+   && chown -R caddy /www
+ 
+ COPY Caddyfile /etc/Caddyfile
+ 
+ USER caddy
+ ENTRYPOINT ["/usr/bin/caddy"]
+ CMD ["--conf", "/etc/Caddyfile", "--log", "stdout", "-agree"]
+ ```
+ 
+ and a corresponding `docker-compose` file:
+ ```yaml
+ version: '3.7'
+ 
+ services:
+   web:
+     restart: always
+     build:
+       context: .
+     image: <your_dockerhub_username>/personal-site
+     ports:
+       - "1111"
+     env_file:
+       - ".env"
+ ```
+ 
+ I try to use alpine docker whenever possible. This image fetches a predefined Caddy version, v1.0.0, with the `cache` and `git` plugins.
+ 
+ We need to pass the `-agree` flag to agree to Let's Encrypt's Subscriber Agreement. Caddy will not run otherwise unless you use `-disable-http-challenge` (or specify http/a port), but we want HTTPS, no?
+ 
+ Deploying the image is just `docker push` once you've signed in via the docker cli. 
+ 
+ ---
+ 
+ ...and that's pretty much it. For your VPS, you'll want to install docker and/or docker-compose, then run the image. If you set up a corresponding docker-compose file, you can do `docker-compose pull && docker-compose up -d`.
+ 
+ If you're using webhooks, don't forget to configure the webhook on github/gitlab/bitbucket/etc.
+ 
+ If configured correctly, you should now be able to git push your static assets and automatically have the container pull them in!
+ 
+ [andrewzahcom]: https://git.sr.ht/~andrewzah/andrewzah.com/tree
+ [base]: https://git.sr.ht/~andrewzah/personal-site/tree/master/templates/base.html
+ [buildit]: https://git.sr.ht/~charles/cdaniels.net/tree/master/bin/buildit
+ [caddy-git]: https://caddyserver.com/docs/http.git
+ [caddy]: https://caddyserver.com/
+ [hugo]: https://gohugo.io/
+ [kp]: ../korean-for-programmers/#finally-a-sentence
+ [lfs]: https://git-lfs.github.com/
+ [macros]: https://git.sr.ht/~andrewzah/personal-site/tree/master/templates/macros.html
+ [makefile]: https://git.sr.ht/~andrewzah/personal-site/tree/master/Makefile
+ [philopp]: https://os.phil-opp.com/
+ [source]: https://git.sr.ht/~andrewzah/personal-site/tree
+ [static-assets]: https://github.com/azah/personal-site-public
+ [templates]: https://git.sr.ht/~andrewzah/personal-site/tree/master/templates
+ [tera]: https://tera.netlify.com/
+ [zola-examples]: https://github.com/getzola/zola/blob/master/EXAMPLES.md
+ [zola-started]: https://www.getzola.org/documentation/getting-started/installation/
+ [zola]: https://getzola.org
+ 
+ ## Conclusion

M sass/components/_highlight.scss => sass/components/_highlight.scss +5 -3
@@ 1,11 1,13 @@ .hl {
-   padding: 2px 0px 2px 2px;
+   padding: 0px 5px 0px 5px;
+   margin-top: 0.5px;
    border-radius: 2px;
+   display: inline-block;
  }
  
  .hl-word {
-   padding: 2px;
-   margin-right: 6px;
+   //padding: 2px;
+   //margin-right: 6px;
  }
  
  .hl-left {