new.sh
#!/bin/sh
set -eu
week="$(date +%Gw%V)"
today="$(date +%Y%m%d)"
clock=""
apply_date() {
local when="$1" mode="$2"
case "$when" in
yesterday) today="$(date -v-1d +%Y%m%d)"; week="$(date -v-1d +%Gw%V)";;
tomorrow) today="$(date -v+1d +%Y%m%d)"; week="$(date -v+1d +%Gw%V)";;
next) today="$(date -v+1w +%Y%m%d)"; week="$(date -v+1w +%Gw%V)";;
last) today="$(date -v-1w +%Y%m%d)"; week="$(date -v-1w +%Gw%V)";;
+[0-9]*)
local n="${when#+}"
if test "$mode" = w; then
today="$(date -v+"${n}"w +%Y%m%d)"; week="$(date -v+"${n}"w +%Gw%V)"
else
today="$(date -v+"${n}"d +%Y%m%d)"; week="$(date -v+"${n}"d +%Gw%V)"
fi;;
-[0-9]*)
local n="${when#-}"
if test "$mode" = w; then
today="$(date -v-"${n}"w +%Y%m%d)"; week="$(date -v-"${n}"w +%Gw%V)"
else
today="$(date -v-"${n}"d +%Y%m%d)"; week="$(date -v-"${n}"d +%Gw%V)"
fi;;
[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9])
today="$when"
week="$(date -jf %Y%m%d "$when" +%Gw%V)";;
*) echo "Unknown date offset: $when" >&2; exit 1;;
esac
clock="$(date -jf %Y%m%d "$today" "+%Y-%m-%dT12:00:00.00%z" | sed 's/\(..\)$/:\1/')"
}
hugo_new() {
if test -n "$clock"; then
set -- --clock "$clock" "$@"
fi
exec hugo new content --editor code "$@"
}
usage() {
cat <<EOF
Usage: $0 <command> [options] [slug]
Commands:
day [-k kind] [-d when] <slug> Create a day post (default kind: daypost)
week [-d when] [slug] Create a week log (no slug) or week post (with slug)
page <path> Create an arbitrary page
Date offsets (-d):
yesterday, tomorrow — shift by one day
next, last — shift by one week
+N, -N — shift by N days (day) or N weeks (week)
YYYYMMDD — specific date
Examples (today: $today, week: $week):
COMMAND CREATES
$0 day meeting-notes log/$week/${today}-meeting-notes/index.md
$0 day -d yesterday meeting-notes log/$week/${today}-meeting-notes/index.md
$0 week log/$week/_index.md
$0 week projects log/$week/projects/index.md
$0 week -d next log/$week/_index.md
$0 week -d next projects log/$week/projects/index.md
$0 page notes/workstation-setup/index.md notes/workstation-setup/index.md
EOF
}
case "${1:-}" in
day)
shift
kind=daypost
while test $# -gt 0; do
case "$1" in
-k) kind="$2"; shift 2;;
-d) apply_date "$2" d; shift 2;;
-*) echo "Unknown option: $1" >&2; exit 1;;
*) slug="$1"; shift;;
esac
done
if test -z "${slug:-}"; then
echo "Usage: $0 day [-k kind] <slug>" >&2
exit 1
fi
hugo_new --kind "$kind" "log/$week/${today}-${slug}/index.md"
;;
week)
shift
slug=""
while test $# -gt 0; do
case "$1" in
-d) apply_date "$2" w; shift 2;;
-*) echo "Unknown option: $1" >&2; exit 1;;
*) slug="$1"; shift;;
esac
done
if test -z "$slug"; then
hugo_new --kind weeklog "log/$week/_index.md"
else
hugo_new --kind weekpost "log/$week/${slug}/index.md"
fi
;;
page)
shift
if test -z "${1:-}"; then
echo "Usage: $0 page <path>" >&2
exit 1
fi
hugo_new "$1"
;;
-h|--help)
usage
exit 0
;;
*)
usage >&2
exit 1
;;
esac
vscode.settings.json
{
"vim.leader": "<space>",
"vim.normalModeKeyBindingsNonRecursive": [
{
"before": ["<leader>", "H"],
"commands": [
{
"command": "workbench.action.tasks.runTask",
"args": "Open hugo page in browser"
}
]
}
]
}
vscode.tasks.json
{
"version": "2.0.0",
"tasks": [
{
"label": "Open hugo page in browser",
"type": "shell",
"command": "bash",
"args": [
"-c",
"FILE='${relativeFile}'; if [[ $FILE != content/*.md ]]; then exit 0; fi; P=${FILE#content/}; P=${P%.md}; P=${P%_index}; P=${P%index}; P=${P%/}; open \"http://localhost:1313/$P/\""
],
"presentation": {
"reveal": "never",
"panel": "shared",
"clear": true
},
"problemMatcher": []
}
]
}
archetypes.daypost.md
---
title: '{{ replace .File.ContentBaseName "-" " " | title }}'
date: '{{ .Date }}'
tags:
- daypost
---
archetypes.weeklog.md
---
{{- define "isoDateYear" -}}
{{- /* Return the ISO year based on the week number */ -}}
{{ $wd := sub (int now.Weekday) 1 }}{{ if lt $wd 0 }}{{ $wd = 6 }}{{ end }}{{ $thu := now.AddDate 0 0 (sub 3 $wd) }}{{ $week := add 1 (div (sub $thu.YearDay 1) 7) }}{{ printf "%d" $thu.Year }}
{{- end -}}
{{- define "isoDateWeek" -}}
{{- /* Return the ISO week number */ -}}
{{ $wd := sub (int now.Weekday) 1 }}{{ if lt $wd 0 }}{{ $wd = 6 }}{{ end }}{{ $thu := now.AddDate 0 0 (sub 3 $wd) }}{{ $week := add 1 (div (sub $thu.YearDay 1) 7) }}{{ printf "%02d" $week }}
{{- end -}}
title: {{ template "isoDateYear" }} Week {{ template "isoDateWeek" }}
date: {{ .Date }} # Set to the date of the week's Monday
isoDate:
Year: {{ template "isoDateYear" }}
Week: {{ template "isoDateWeek" }}
type: weeklog
---
## Weekposts
{{< weekposts >}}
## Monday
### Goals
...
### Other
...
### Pages
{{< daypostsFromOffset 0 >}}
## Tuesday
### Goals
...
### Other
...
### Pages
{{< daypostsFromOffset 1 >}}
## Wednesday
### Goals
...
### Other
...
### Pages
{{< daypostsFromOffset 2 >}}
## Thursday
### Goals
...
### Other
...
### Pages
{{< daypostsFromOffset 3 >}}
## Friday
### Goals
...
### Other
...
### Pages
{{< daypostsFromOffset 4 >}}
archetypes.weekpost.md
---
{{- define "isoWeekId" -}}
{{- /* Return the ISO year based on the week number */ -}}
{{ $wd := sub (int now.Weekday) 1 }}{{ if lt $wd 0 }}{{ $wd = 6 }}{{ end }}{{ $thu := now.AddDate 0 0 (sub 3 $wd) }}{{ $week := add 1 (div (sub $thu.YearDay 1) 7) }}{{ printf "%dw%02d" $thu.Year $week }}
{{- end -}}
title: '{{ template "isoWeekId" }} {{ replace .File.ContentBaseName "-" " " | title }}'
date: '{{ .Date }}'
tags:
- weekpost
---
content.user.html
<p>
This tool generates links to look up users by username.
It can't know anything about our real directory, so a typo'd user will generate invalid links.
</p>
<style>
#user-info th,
#user-info td {
text-align: left;
}
#user-info th {
padding-right: 1em;
}
</style>
<template id="user-template">
<h2 data-field="username"></h2>
<table>
<tr><th>Slack</th><td><a target="_blank" data-field="slack"></a></td></tr>
<tr><th>Email</th><td><a data-field="email"></a></td></tr>
</table>
</template>
<div id="user-info">
<h2>No user</h2>
<p>Set <code>?u=USERNAME</code> in the URL bar</p>
</div>
<script>
(function() {
const params = new URLSearchParams(window.location.search);
const username = params.get('u');
if (!username) return;
const template = document.getElementById('user-template');
const clone = template.content.cloneNode(true);
clone.querySelector('[data-field="username"]').textContent = username;
const slack = clone.querySelector('[data-field="slack"]');
slack.href = `https://example.slack.com/team/${username}`;
slack.textContent = `@${username}`;
const emailAddr = `${username}@example.com`;
const email = clone.querySelector('[data-field="email"]');
email.href = `mailto:${emailAddr}`;
email.textContent = emailAddr;
const container = document.getElementById('user-info');
container.replaceChildren(clone);
})();
</script>
<!-- -*- mode: html -*- -->
markup.render-link.html
{{- /*
Compute display text for <https://example.com> -style "autolinks".
For recognized services, replace the bare URL with a human-readable label.
*/ -}}
{{- $linkText := .Text }}
{{- $useCite := false }}
{{- if and $u.IsAbs (eq .Text .Destination) }}
{{- /* GitHub: shorten to org/repo, org/repo#number, or org/repo@commit/path */}}
{{- if hasPrefix .Destination "https://github.com/" }}
{{- $path := strings.TrimPrefix "https://github.com/" .Destination }}
{{- $parts := split $path "/" }}
{{- $org := index $parts 0 }}
{{- $repo := index $parts 1 }}
{{- $text := printf "%s/%s" $org $repo }}
{{- if and (ge (len $parts) 4) (or (eq (index $parts 2) "issues") (eq (index $parts 2) "pull")) }}
{{- /* Issue or PR URL: append #number */}}
{{- $text = printf "%s/%s#%s" $org $repo (index $parts 3) }}
{{- else if and (ge (len $parts) 4) (or (eq (index $parts 2) "tree") (eq (index $parts 2) "blob")) }}
{{- /* Tree or blob URL: append @short-hash/subpath */}}
{{- $hash := index $parts 3 }}
{{- $short := substr $hash 0 7 }}
{{- $rest := after 4 $parts }}
{{- $text = printf "%s/%s@%s/%s" $org $repo $short (delimit $rest "/") }}
{{- end }}
{{- $linkText = printf "[GH] %s" $text }}
{{- /* Confluence wiki: show space key and page title */}}
{{- else if findRE `^https://example\.atlassian\.net/wiki/spaces/` .Destination }}
{{- $path := replaceRE `^https://example\.atlassian\.net/wiki/spaces/` "" .Destination }}
{{- $parts := split $path "/" }}
{{- $space := index $parts 0 }}
{{- /* Page title is the 4th path segment; + encodes spaces in Confluence URLs */}}
{{- $title := index $parts 3 | replaceRE `\+` " " }}
{{- $linkText = printf "[Confluence: %s] %s" $space $title }}
{{- $useCite = true }}
{{- /* Twitter/X profile or tweet; both twitter.com and x.com are supported */}}
{{- else if or (hasPrefix .Destination "https://twitter.com/") (hasPrefix .Destination "https://x.com/") }}
{{- $twitterBase := cond (hasPrefix .Destination "https://twitter.com/") "https://twitter.com/" "https://x.com/" }}
{{- $path := strings.TrimPrefix $twitterBase .Destination }}
{{- $parts := split $path "/" }}
{{- $user := index $parts 0 }}
{{- if and (ge (len $parts) 3) (eq (index $parts 1) "status") }}
{{- /* Tweet URL: twitter.com/user/status/id */}}
{{- $linkText = printf "[Twitter] tweet from @%s" $user }}
{{- else }}
{{- /* Profile URL: twitter.com/user */}}
{{- $linkText = printf "[Twitter] @%s" $user }}
{{- end }}
{{- /* Wikipedia: convert article slug to title (underscores to spaces) */}}
{{- else if findRE `^https://[a-z]+\.wikipedia\.org/wiki/` .Destination }}
{{- $title := replaceRE `^https://[a-z]+\.wikipedia\.org/wiki/` "" .Destination | replaceRE `_` " " }}
{{- $linkText = printf "[WP] %s" $title }}
{{- $useCite = true }}
{{- /* Jira ticket: extract and show the ticket ID (e.g. PROJ-123) */}}
{{- else if findRE `^https://example\.atlassian\.net/.*[A-Z]+-\d+` .Destination }}
{{- $ticket := replaceRE `.*?([A-Z]+-\d+).*` "$1" .Destination }}
{{- $linkText = printf "[Jira] %s" $ticket }}
{{- end }}
{{- end }}
partials.dayPosts.html
{{- $section := .Section -}}
{{- $start := time (.Date | time.Format "2006-01-02") -}}
{{- $end := $start.AddDate 0 0 1 -}}
{{- $pages := where $section.RegularPages "Date" "ge" $start -}}
{{- $pages = where $pages "Date" "lt" $end -}}
{{- $pages = where $pages "Params.tags" "intersect" (slice "daypost") -}}
{{- if $pages }}
<ul>
{{- range $pages.ByDate }}
<li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li>
{{- end }}
</ul>
{{- else }}
<p>None</p>
{{- end }}
partials.weekPosts.html
{{- $section := .Section -}}
{{- $pages := where $section.RegularPages "Params.tags" "intersect" (slice "weekpost") -}}
{{- if $pages }}
<ul>
{{- range $pages.ByDate }}
<li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li>
{{- end }}
</ul>
{{- else }}
<p>None</p>
{{- end }}
shortcodes.dayPostsFromOffset.html
{{- $offset := .Get 0 | default 0 | int -}}
{{- $date := .Page.Date -}}
{{- $dateWithOffset := $date.AddDate 0 0 $offset -}}
{{- partial "dayposts.html" (dict "Section" .Page.CurrentSection "Date" $dateWithOffset) -}}
shortcodes.link.html
{{ with .Site.GetP|age (.Get 0) }}<a href="{{ .Permalink }}"><cite>{{ .Title }}</cite></a>{{ end }}
shortcodes.u.html
<a class="userlink" href="{{ .Site.BaseURL }}tools/user/?u={{ .Get 0 }}>~{{ .Get 0 }}</a>