about summary refs log tree commit diff
path: root/web/homepage
diff options
context:
space:
mode:
Diffstat (limited to 'web/homepage')
-rw-r--r--web/homepage/default.nix76
-rw-r--r--web/homepage/entries.nix47
-rw-r--r--web/homepage/footer.html2
-rw-r--r--web/homepage/header.html35
-rw-r--r--web/homepage/nginx.nix79
-rw-r--r--web/homepage/static/favicon.webpbin0 -> 11554 bytes
-rw-r--r--web/homepage/static/jetbrains-mono-bold-italic.woff2bin0 -> 53364 bytes
-rw-r--r--web/homepage/static/jetbrains-mono-bold.woff2bin0 -> 49892 bytes
-rw-r--r--web/homepage/static/jetbrains-mono-italic.woff2bin0 -> 50936 bytes
-rw-r--r--web/homepage/static/jetbrains-mono.woff2bin0 -> 48700 bytes
-rw-r--r--web/homepage/static/tazjin.css142
11 files changed, 381 insertions, 0 deletions
diff --git a/web/homepage/default.nix b/web/homepage/default.nix
new file mode 100644
index 000000000000..d2905a7eb6ca
--- /dev/null
+++ b/web/homepage/default.nix
@@ -0,0 +1,76 @@
+# Assembles the website index and configures an nginx instance to
+# serve it.
+#
+# The website is made up of a simple header&footer and content
+# elements for things such as blog posts and projects.
+#
+# Content for the blog is in //web/blog instead of here.
+{ pkgs, lib, ... }:
+
+with pkgs;
+with nix.yants;
+
+let
+  inherit (builtins) readFile replaceStrings sort;
+  inherit (third_party) writeFile runCommandNoCC;
+
+  # The different types of entries on the homepage.
+  entryClass = enum "entryClass" [ "blog" "project" "misc" ];
+
+  # The definition of a single entry.
+  entry = struct "entry" {
+    class = entryClass;
+    title = string;
+    url = string;
+    date = int; # epoch
+    description = option string;
+  };
+
+  escape = replaceStrings [ "<" ">" "&" "'" ] [ "&lt;" "&gt;" "&amp;" "&#39;" ];
+
+  postToEntry = defun [ web.blog.post entry ] (post: {
+    class = "blog";
+    title = post.title;
+    url = "/blog/${post.key}";
+    date = post.date;
+  });
+
+  formatDate = defun [ int string ] (date: readFile (runCommandNoCC "date" {} ''
+    date --date='@${toString date}' '+%Y-%m-%d' > $out
+  ''));
+
+  formatEntryDate = defun [ entry string ] (entry: entryClass.match entry.class {
+    blog = "Blog post from ${formatDate entry.date}";
+    project = "Project from ${formatDate entry.date}";
+    misc = "Posted on ${formatDate entry.date}";
+  });
+
+  entryToDiv = defun [ entry string ] (entry: ''
+    <a href="${entry.url}" class="entry ${entry.class}">
+      <div>
+        <p class="entry-title">${escape entry.title}</p>
+        ${
+          lib.optionalString ((entry ? description) && (entry.description != null))
+          "<p class=\"entry-description\">${escape entry.description}</p>"
+        }
+        <p class="entry-date">${formatEntryDate entry}</p>
+      </div>
+    </a>
+  '');
+
+  index = entries: third_party.writeText "index.html" (lib.concatStrings (
+    [ (builtins.readFile ./header.html) ]
+    ++ (map entryToDiv (sort (a: b: a.date > b.date) entries))
+    ++ [ (builtins.readFile ./footer.html) ]
+  ));
+
+  homepage = index ((map postToEntry web.blog.posts) ++ (import ./entries.nix));
+  website = runCommandNoCC "website" {} ''
+    mkdir $out
+    cp ${homepage} $out/index.html
+    cp -r ${./static} $out/static
+  '';
+in third_party.callPackage ./nginx.nix {
+  inherit website;
+  blog = web.blog;
+}
diff --git a/web/homepage/entries.nix b/web/homepage/entries.nix
new file mode 100644
index 000000000000..d204090330ef
--- /dev/null
+++ b/web/homepage/entries.nix
@@ -0,0 +1,47 @@
+[
+  {
+    class = "project";
+    title = "depot";
+    url = "https://git.tazj.in/about";
+    date = 1576800000;
+    description = "Merging all of my projects into a single, Nix-based monorepo";
+  }
+  {
+    class = "project";
+    title = "Nixery";
+    url = "https://github.com/google/nixery";
+    date = 1565132400;
+    description = "A Nix-backed container registry that builds container images on demand";
+  }
+  {
+    class = "project";
+    title = "kontemplate";
+    url = "https://git.tazj.in/about/ops/kontemplate";
+    date = 1486550940;
+    description = "Simple file templating tool built for Kubernetes resources";
+  }
+  {
+    class = "misc";
+    title = "dottime";
+    url = "https://dotti.me/";
+    date = 1560898800;
+    description = "A universal convention for conveying time (by edef <3)";
+  }
+  {
+    class = "project";
+    title = "journaldriver";
+    url = "https://git.tazj.in/about/ops/journaldriver";
+    date = 1527375600;
+    description = "Small daemon to forward logs from journald to Stackdriver Logging";
+  }
+  {
+    class = "misc";
+    title = "Principia Discordia";
+    url = "https://principiadiscordia.com/book/1.php";
+    date = 1495494000;
+    description = ''
+      The Principia is a short book I read as a child, and didn't
+      understand until much later. It shaped much of my world view.
+    '';
+  }
+]
diff --git a/web/homepage/footer.html b/web/homepage/footer.html
new file mode 100644
index 000000000000..2f17135066e8
--- /dev/null
+++ b/web/homepage/footer.html
@@ -0,0 +1,2 @@
+  </div>
+</body>
diff --git a/web/homepage/header.html b/web/homepage/header.html
new file mode 100644
index 000000000000..ec81fa04dc05
--- /dev/null
+++ b/web/homepage/header.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<head><meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <meta name="description" content="tazjin&#39;s blog">
+  <link rel="stylesheet" type="text/css" href="static/tazjin.css" media="all">
+  <link rel="icon" type="image/webp" href="/static/favicon.webp">
+  <title>tazjin&#39;s interblag</title>
+</head>
+<body class="dark">
+  <header>
+    <h1>
+      <a class="interblag-title" href="/">tazjin&#39;s interblag</a>
+    </h1>
+    <hr>
+  </header>
+  <div class="introduction">
+    <p>Hello, illuminated visitor.</p>
+    <p>
+      I'm tazjin. Usually you can find
+      me <a class="dark-link" href="https://git.tazj.in/about">programming computers</a>
+      using tools such as <a class="dark-link" href="https://nixos.org/nix">Nix</a>
+      and <a class="dark-link" href="https://www.gnu.org/software/emacs/">Emacs</a>,
+      cuddling <a class="dark-link" href="https://twitter.com/edefic">people I love</a>
+      or posting nonsense <a class="dark-link" href="https://twitter.com/tazjin">on the
+      internet</a>.
+    </p>
+    <p>
+      Below is a collection of
+      my <span class="project">projects</span>, <span class="blog">blog
+      posts</span> and some <span class="misc">random things</span> by
+      me or others. If you'd like to get in touch about anything, send
+      me a mail at mail@[this domain] or ping me on IRC or Twitter.
+    </p>
+  </div>
+  <div class="entry-container">
diff --git a/web/homepage/nginx.nix b/web/homepage/nginx.nix
new file mode 100644
index 000000000000..100c0cc9ee3a
--- /dev/null
+++ b/web/homepage/nginx.nix
@@ -0,0 +1,79 @@
+# This file creates an nginx server that serves the blog on port 8080.
+#
+# It's not intended to be the user-facing nginx.
+{
+  # third_party attributes supplied by callPackage
+  writeText, writeShellScriptBin, nginx, lib,
+
+  # website content
+  blog, website
+}:
+
+let
+  inherit (builtins) hasAttr filter map;
+  inherit (pkgs.third_party) ;
+
+  oldRedirects = lib.concatStringsSep "\n" (map (post: ''
+    location ~* ^(/en)?/${post.oldKey} {
+      # TODO(tazjin): 301 once this works
+      return 302 https://tazj.in/blog/${post.key};
+    }
+  '') (filter (hasAttr "oldKey") blog.posts));
+
+  config = writeText "homepage-nginx.conf" ''
+    daemon off;
+    worker_processes 1;
+    error_log stderr;
+    pid /tmp/nginx-homepage.pid;
+
+    events {
+      worker_connections  1024;
+    }
+
+    http {
+      include ${nginx}/conf/mime.types;
+      fastcgi_temp_path /tmp/nginx-homepage;
+      uwsgi_temp_path /tmp/nginx-homepage;
+      scgi_temp_path /tmp/nginx-homepage;
+      client_body_temp_path /tmp/nginx-homepage;
+      proxy_temp_path /tmp/nginx-homepage;
+      sendfile on;
+
+      # Logging is handled by the primary nginx server
+      access_log off;
+
+      server {
+        listen 8080 default_server;
+        server_name tazj.in;
+        root ${website};
+
+        ${oldRedirects}
+
+        location /blog {
+          alias ${blog.rendered};
+
+          if ($request_uri ~ ^/(.*)\.html$) {
+            return 302 /$1;
+          }
+
+          try_files $uri $uri.html $uri/ =404;
+        }
+      }
+
+      server {
+        listen 8080;
+        server_name www.tazj.in;
+        return 301 https://tazj.in$request_uri;
+      }
+    }
+  '';
+in writeShellScriptBin "homepage" ''
+  if [[ -v CONTAINER_SETUP ]]; then
+    cd /run
+    echo 'nogroup:x:30000:nobody' >> /etc/group
+    echo 'nobody:x:30000:30000:nobody:/tmp:/bin/bash' >> /etc/passwd
+  fi
+
+  mkdir -p /tmp/nginx-homepage
+  exec ${nginx}/bin/nginx -c ${config}
+''
diff --git a/web/homepage/static/favicon.webp b/web/homepage/static/favicon.webp
new file mode 100644
index 000000000000..f99c9085340b
--- /dev/null
+++ b/web/homepage/static/favicon.webp
Binary files differdiff --git a/web/homepage/static/jetbrains-mono-bold-italic.woff2 b/web/homepage/static/jetbrains-mono-bold-italic.woff2
new file mode 100644
index 000000000000..34b5c69ae1cf
--- /dev/null
+++ b/web/homepage/static/jetbrains-mono-bold-italic.woff2
Binary files differdiff --git a/web/homepage/static/jetbrains-mono-bold.woff2 b/web/homepage/static/jetbrains-mono-bold.woff2
new file mode 100644
index 000000000000..84a008af7edb
--- /dev/null
+++ b/web/homepage/static/jetbrains-mono-bold.woff2
Binary files differdiff --git a/web/homepage/static/jetbrains-mono-italic.woff2 b/web/homepage/static/jetbrains-mono-italic.woff2
new file mode 100644
index 000000000000..85fd4687891e
--- /dev/null
+++ b/web/homepage/static/jetbrains-mono-italic.woff2
Binary files differdiff --git a/web/homepage/static/jetbrains-mono.woff2 b/web/homepage/static/jetbrains-mono.woff2
new file mode 100644
index 000000000000..d5b94cb9e7db
--- /dev/null
+++ b/web/homepage/static/jetbrains-mono.woff2
Binary files differdiff --git a/web/homepage/static/tazjin.css b/web/homepage/static/tazjin.css
new file mode 100644
index 000000000000..68e72577c37a
--- /dev/null
+++ b/web/homepage/static/tazjin.css
@@ -0,0 +1,142 @@
+/* Jetbrains Mono font from https://www.jetbrains.com/lp/mono/
+   licensed under Apache 2.0. Thanks, Jetbrains! */
+@font-face {
+    font-family: jetbrains-mono;
+    src: url(jetbrains-mono.woff2);
+}
+
+@font-face {
+    font-family: jetbrains-mono;
+    font-weight: bold;
+    src: url(jetbrains-mono-bold.woff2);
+}
+
+@font-face {
+    font-family: jetbrains-mono;
+    font-style: italic;
+    src: url(jetbrains-mono-italic.woff2);
+}
+
+@font-face {
+    font-family: jetbrains-mono;
+    font-weight: bold;
+    font-style: italic;
+    src: url(jetbrains-mono-bold-italic.woff2);
+}
+
+/* Generic-purpose styling */
+
+body {
+    margin: 40px auto;
+    line-height: 1.6;
+    font-size: 18px;
+    padding: 0 10px;
+    font-family: jetbrains-mono, monospace;
+}
+
+p, a :not(.uncoloured-link) {
+    color: inherit;
+}
+
+h1, h2, h3 {
+    line-height: 1.2
+}
+
+/* Homepage styling */
+
+.dark {
+    max-width: 800px;
+    background-color: #181818;
+    color: #e4e4ef;
+}
+
+.dark-link, .interblag-title {
+    color: #96a6c8;
+}
+
+.entry-container {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+    justify-content: flex-start;
+}
+
+.interblag-title {
+    text-decoration: none;
+}
+
+.entry {
+    width: 42%;
+    margin: 5px;
+    padding-left: 7px;
+    padding-right: 5px;
+    border: 2px solid;
+    border-radius: 5px;
+    flex-grow: 1;
+    text-decoration: none;
+}
+
+.misc {
+    color: #268bd2;
+    border-color: #268bd2;
+}
+
+.project {
+    color: #9e95c7;
+    border-color: #9e95c7;
+}
+
+.blog {
+    color: #95a99f;
+    border-color: #95a99f;
+}
+
+.entry-title {
+    color: inherit !important;
+    font-weight: bold;
+    text-decoration: none;
+}
+
+.entry-date {
+    font-style: italic;
+}
+
+/* Blog styling */
+
+.light {
+    max-width: 650px;
+    color: #383838;
+}
+
+.blog-title {
+    color: inherit;
+    text-decoration: none;
+}
+
+.footer {
+    text-align: right;
+}
+
+.date {
+    text-align: right;
+    font-style: italic;
+    float: right;
+}
+
+.inline {
+    display: inline;
+}
+
+.lod {
+    text-align: center;
+}
+
+pre {
+    min-width: 100%;
+    /* some code snippets escape to the side, but I don't want to wrap them */
+    width: max-content;
+}
+
+img {
+    max-width: 100%;
+}