Compare commits

..

4 Commits

Author SHA1 Message Date
18c2c898aa updates open graph data 2025-04-25 22:32:06 -06:00
451e860697 adds headshot resource support 2025-04-25 21:33:57 -06:00
b89373b478 adds article archetype 2025-04-25 20:17:43 -06:00
b6f74485a4 moves js into the asset pipeline 2025-04-25 20:05:33 -06:00
21 changed files with 177 additions and 95 deletions

View File

@ -8,6 +8,57 @@ Developed in Hugo.
Navigate to the project directory and: Navigate to the project directory and:
```
npm install
```
Then, to serve the site locally:
``` ```
hugo server hugo server
``` ```
## Articles
see `/archetypes/article.md` for the article template. You can create a new article with:
```
hugo new articles/2023-01-01-my-new-article.md
```
This will create a new article in the `content/articles` directory with the current date and the title you provide. You can then edit the file to add your content.
### Head shots
Optionally you can add a headshot photo to your article. To do this:
1. Place your image file in the `/assets/headshots/` directory
2. Add a `headshot` field to your article's front matter with just the filename. For example:
```yaml
headshot: "firstname-lastname.jpg"
```
*Note: Name is case sensitive, might as well use lowercase letters and hyphens in your filename.*
### Narrator links
You can add links to an article that relate to the narrator. To do this, add a `links` field to the front matter of the article. The value should be a list of objects, each with a `text` and `url` field. For example:
```
links:
- text: "My Website"
url: "https://example.com"
- text: "My Twitter"
url: "https://twitter.com/example"
```
This will include the links in the article page. The links will be displayed as a list with the text as the link text and the URL as the link target.
### Open Graph Image
You can add Open Graph image (for social media sharing) to an article. To do this, add a `ogImage` field to the front matter of the article. The value should be the path to the image file. For example:
```yaml
ogImage: "/images/my-image.jpg"
```
*Note: The image should be at least 1200x630 pixels for best results. Make sure to place the image in `/static/images/` directory so it can be served correctly. The path should be relative to the static directory.*

14
archetypes/articles.md Normal file
View File

@ -0,0 +1,14 @@
---
narrator: ""
subject: ""
facilitator: ""
date: {{ dateFormat "2006-01-02" .Date }} # YYYY-MM-DD
approved: "" # YYYY-MM-DD
summary: ""
location: ""
topics: []
headshot: "placeholder-headshot.png"
links:
- text: ""
url: ""
---

View File

@ -1,6 +0,0 @@
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---

44
assets/css/article.css Normal file
View File

@ -0,0 +1,44 @@
.interviewer-question {
font-style: italic;
color: #444;
margin-left: -1rem;
}
.article-title--single .article-title__narrator {
@apply mb-2 block font-light;
}
.article-title--single .article-title__subject {
font-size: 1.5em;
}
.article-title--list .article-title__narrator::after {
content: ":";
}
.article-title--list .article-title__subject {
@apply font-light;
}
.wompum-radial-grid {
@apply absolute w-full h-full top-0 left-0;
}
/* Narrator headshot */
.narrator__container {
@apply relative w-48 mb-2 mx-auto md:mx-0 bg-white rounded-full border-4 border-white;
}
.narrator__frame {
@apply relative p-4;
}
.narrator__frame img {
@apply w-full rounded-full object-cover relative z-10 bg-white text-center border-4 border-white grid place-items-center;
aspect-ratio: 1;
}
.narrator__wompum {
@apply absolute inset-0 w-full h-full;
}

View File

@ -6,49 +6,6 @@ a:hover {
@apply text-pine-900; @apply text-pine-900;
} }
.interviewer-question {
font-style: italic;
color: #444;
margin-left: -1rem;
}
.article-title--single .article-title__narrator {
@apply mb-2 block font-light;
}
.article-title--single .article-title__subject {
font-size: 1.5em;
}
.article-title--list .article-title__narrator::after {
content: ":";
}
.article-title--list .article-title__subject {
@apply font-light;
}
.wompum-radial-grid {
@apply absolute w-full h-full top-0 left-0;
}
.narrator__container {
@apply relative;
}
.narrator__frame {
@apply relative p-4;
}
.narrator__image {
@apply w-full rounded-full object-cover relative z-10 bg-white text-center border-4 border-white grid place-items-center;
aspect-ratio: 1;
}
.narrator__wompum {
@apply absolute inset-0 w-full h-full;
}
.tag { .tag {
@apply p-2 bg-sand-100 border border-transparent hover:border-sand-500 rounded-lg whitespace-nowrap hover:text-gray-900 hover:opacity-100 no-underline; @apply p-2 bg-sand-100 border border-transparent hover:border-sand-500 rounded-lg whitespace-nowrap hover:text-gray-900 hover:opacity-100 no-underline;
} }

View File

@ -45,3 +45,4 @@ body {
@import "components/wompum.css"; @import "components/wompum.css";
@import "main.css"; @import "main.css";
@import "article.css";

View File

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

@ -12,7 +12,7 @@ title = 'Protocol Oral History Project'
[params] [params]
description = "The Protocol Oral History Project chronicles the development of internet protocols and standards through interviews with key contributors." description = "The Protocol Oral History Project chronicles the development of internet protocols and standards through interviews with key contributors."
images = ["/images/default-og.jpg"] # Will be replaced by wompum generation openGraphImage = "/images/og-default.jpg"
twitterSite = "" twitterSite = ""
facebookAppID = "" facebookAppID = ""
footer = """ footer = """

View File

@ -7,7 +7,7 @@ approved: 2025-03-20
summary: "Drawing on many ancestral traditions and the experience of her own body, Asia Dorsey learns and teaches the pattern language of a healthy gut." summary: "Drawing on many ancestral traditions and the experience of her own body, Asia Dorsey learns and teaches the pattern language of a healthy gut."
location: "Denver CO" location: "Denver CO"
topics: [ancestors, food, health, indigeneity] topics: [ancestors, food, health, indigeneity]
headshot: "/headshots/placeholder-headshot.png" headshot: "placeholder-headshot.png"
links: links:
- text: "Bugs Bones & Botany" - text: "Bugs Bones & Botany"
url: "https://www.bonesbugsandbotany.com" url: "https://www.bonesbugsandbotany.com"

View File

@ -6,7 +6,7 @@ date: 2024-10-10
approved: 2024-10-11 approved: 2024-10-11
summary: "After widespread resistance to codes of conduct in open-source software communities, Coraline Ada Ehmke's Contributor Covenant became the most popular code of conduct in the ecosystem." summary: "After widespread resistance to codes of conduct in open-source software communities, Coraline Ada Ehmke's Contributor Covenant became the most popular code of conduct in the ecosystem."
location: "Chicago, USA" location: "Chicago, USA"
headshot: "/headshots/placeholder-headshot.png" headshot: "placeholder-headshot.png"
topics: [code of conduct, dispute resolution, gender, open source, organizations, software] topics: [code of conduct, dispute resolution, gender, open source, organizations, software]
--- ---

View File

@ -6,7 +6,7 @@ date: 2024-10-29
approved: 2024-12-16 approved: 2024-12-16
summary: "Good Market is a digital commons for enterprises that prioritize people and the planet over profit. It enables communities to set and enforce their own standards for doing business." summary: "Good Market is a digital commons for enterprises that prioritize people and the planet over profit. It enables communities to set and enforce their own standards for doing business."
location: "Sri Lanka / United States" location: "Sri Lanka / United States"
headshot: "/headshots/placeholder-headshot.png" headshot: "placeholder-headshot.png"
topics: [economics, organizations, ecology, standards] topics: [economics, organizations, ecology, standards]
--- ---

View File

@ -6,7 +6,7 @@ date: 2024-12-13
approved: 2025-03-04 approved: 2025-03-04
summary: "A diplomat for Bangladesh describes the role of protocol in high-profile international visits and treaty negotiations." summary: "A diplomat for Bangladesh describes the role of protocol in high-profile international visits and treaty negotiations."
location: "Dhaka, Bangladesh" location: "Dhaka, Bangladesh"
headshot: "/headshots/placeholder-headshot.png" headshot: "placeholder-headshot.png"
topics: [diplomacy, government, friendship] topics: [diplomacy, government, friendship]
--- ---

View File

@ -6,7 +6,7 @@ date: 2024-12-06
approved: 2025-04-01 approved: 2025-04-01
summary: "A career-long journey to build online social networks that cannot be controlled by a single company, culminating with the ActivityPub standard." summary: "A career-long journey to build online social networks that cannot be controlled by a single company, culminating with the ActivityPub standard."
location: "Montreal, Canada" location: "Montreal, Canada"
headshot: "/headshots/placeholder-headshot.png" headshot: "placeholder-headshot.png"
links: links:
- text: Website - text: Website
url: https://evanp.me/ url: https://evanp.me/

View File

@ -6,7 +6,7 @@ date: 2024-11-04
approved: 2024-12-02 approved: 2024-12-02
summary: "As a sport often played with no referees, ultimate frisbee has developed a strong set of norms for addressing conflict and self-governing." summary: "As a sport often played with no referees, ultimate frisbee has developed a strong set of norms for addressing conflict and self-governing."
location: "East Greenbush, NY USA" location: "East Greenbush, NY USA"
headshot: "/headshots/placeholder-headshot.png" headshot: "placeholder-headshot.png"
topics: [frisbee, sports, organizations, dispute resolution] topics: [frisbee, sports, organizations, dispute resolution]
--- ---

View File

@ -15,7 +15,7 @@
{{ end }} {{ end }}
<!-- Basic SEO --> <!-- Basic SEO -->
<title>{{ $title }}</title> <title>{{ $title }}{{ if .Params.narrator }} - {{ .Site.Title }}{{ end }}</title>
{{/* Generate description from summary, description, or default site description */}} {{/* Generate description from summary, description, or default site description */}}
{{ $description := "" }} {{ $description := "" }}
@ -36,52 +36,47 @@
{{ end }} {{ end }}
<!-- Open Graph / Facebook --> <!-- Open Graph / Facebook -->
<meta property="og:site_name" content="{{ .Site.Title }}" />
<meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}" /> <meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}" />
<meta property="og:url" content="{{ .Permalink }}" /> <meta property="og:url" content="{{ .Permalink }}" />
<meta property="og:title" content="{{ $title }}" /> <meta property="og:title" content="{{ $title }}" />
<meta property="og:description" content="{{ $description }}" /> <meta property="og:description" content="{{ $description }}" />
{{ with .Params.images | default .Site.Params.images }} {{ with .Params.ogImage | default .Site.Params.openGraphImage }}
<meta property="og:image" content="{{ index . 0 | absURL }}" /> <meta property="og:image" content="{{ . | absURL }}" />
{{ end }}
{{ with .Site.Params.facebookAppID }}
<meta property="fb:app_id" content="{{ . }}" />
{{ end }} {{ end }}
<!-- Twitter --> <!-- Twitter -->
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="{{ $title }}" /> <meta name="twitter:title" content="{{ $title }}" />
<meta name="twitter:description" content="{{ $description }}" /> <meta name="twitter:description" content="{{ $description }}" />
{{ with .Params.images }} {{ with .Params.ogImage | default .Site.Params.openGraphImage }}
<meta name="twitter:image" content="{{ index . 0 | absURL }}" /> <meta name="twitter:image" content="{{ . | absURL }}" />
{{ end }} {{ end }}
<!-- Article Specific --> <!-- Article Specific -->
{{ if and .IsPage (eq .Type "articles") }} {{ if and .IsPage (eq .Type "articles") }}
<meta property="article:published_time" content="{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}" /> <meta property="article:published_time" content="{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}" />
<meta property="article:modified_time" content="{{ .Lastmod.Format "2006-01-02T15:04:05Z07:00" }}" /> <meta property="article:modified_time" content="{{ .Lastmod.Format "2006-01-02T15:04:05Z07:00" }}" />
<meta property="article:section" content="Oral History" /> <meta property="article:section" content="Oral History" />
{{ with .Params.topics }} {{ with .Params.topics }}
{{ range . }} {{ range . }}
<meta property="article:tag" content="{{ . }}" /> <meta property="article:tag" content="{{ . }}" />
{{ end }} {{ end }}
{{ end }}
{{ end }} {{/* Author information using standard meta topics instead of article:author */}}
{{ with .Params.narrator }}
{{/* Author information using standard meta topics instead of article:author */}} <meta name="author" content="{{ . }}" />
{{ with .Params.narrator }} {{ end }}
<meta name="author" content="{{ . }}" /> {{ with .Params.facilitator }}
{{ end }} <meta name="interviewer" content="{{ . }}" />
{{ with .Params.facilitator }} {{ end }}
<meta name="interviewer" content="{{ . }}" />
{{ end }}
{{ end }} {{ end }}
<!-- Canonical URL --> <!-- Canonical URL -->
<link rel="canonical" href="{{ .Permalink }}" /> <link rel="canonical" href="{{ .Permalink }}" />
<!-- CSS Variables and Styles --> <!-- CSS Styles -->
{{ partial "css-variables.html" . }}
{{ partial "css.html" . }} {{ partial "css.html" . }}
</head> </head>
<body class=""> <body class="">
@ -90,8 +85,13 @@
{{ block "main" . }}{{ end }} {{ block "main" . }}{{ end }}
</div> </div>
{{ partial "footer.html" . }} {{ partial "footer.html" . }}
<script src="/js/sigil.js"></script>
<script src="/js/colorCalculator.js"></script> {{ $js := resources.Match "js/*.js" | resources.Concat "js/bundle.js" }}
<script src="/js/wompum.js"></script> {{ if hugo.IsProduction }}
{{ $js = $js | minify | fingerprint }}
<script src="{{ $js.RelPermalink }}" integrity="{{ $js.Data.Integrity }}" crossorigin="anonymous"></script>
{{ else }}
<script src="{{ $js.RelPermalink }}"></script>
{{ end }}
</body> </body>
</html> </html>

View File

@ -5,14 +5,16 @@
<header class="mb-4 wompum-container wompum-container--wide-gap aspect-2/1 md:aspect-3/1">{{ partial "article-wompum.html" . }}</header> <header class="mb-4 wompum-container wompum-container--wide-gap aspect-2/1 md:aspect-3/1">{{ partial "article-wompum.html" . }}</header>
<div class="flex md:flex-row flex-col gap-4 mt-4"> <div class="flex md:flex-row flex-col gap-4 mt-4">
<aside class="md:sticky md:top-0 md:h-screen md:overflow-y-auto lg:w-1/3 p-4 font-iosevka <aside class="md:sticky md:top-24 md:h-screen lg:w-1/3 p-4 font-iosevka">
{{ if .Params.headshot }}-mt-24{{ end }} {{ $headshot := resources.GetMatch (printf "**/%s" (strings.TrimPrefix "/" .Params.headshot)) }}
"> {{ if and .Params.headshot $headshot }}
{{ if .Params.headshot }} <div class="narrator__container -mt-24" data-text="{{ .Params.narrator }}">
<div class="narrator__container w-48 mb-2 mx-auto md:mx-0 bg-white rounded-full border-4 border-white" data-text="{{ .Params.narrator }}"> {{ partial "image.html" (dict
<div class="narrator__frame"> "resource" $headshot
<img src="{{ .Params.headshot }}" alt="Photo of {{ .Params.narrator }}" class="narrator__image" loading="lazy"> "width" "192"
</div> "class" "narrator__frame"
"alt" (printf "Photo of %s" .Params.narrator)
) }}
</div> </div>
{{ end }} {{ end }}
<div class="md:block hidden">{{ partial "article-metadata.html" . }}</div> <div class="md:block hidden">{{ partial "article-metadata.html" . }}</div>

View File

@ -0,0 +1,19 @@
{{ $width := .width }}
{{ $height := default $width .height }}
{{ $class := .class }}
{{ $resource := .resource }}
{{ $alt := .alt }}
{{ with $resource }}
{{ $image := .Fit (printf "%dx%d webp" (int $width) (int $height)) }}
{{ $fallback := .Fit (printf "%dx%d" (int $width) (int $height)) }}
<picture class="{{ $class }} block">
<source srcset="{{ $image.RelPermalink }}" type="image/webp">
<img
src="{{ $fallback.RelPermalink }}"
alt="{{ $alt }}"
width="{{ $width }}"
height="{{ $height }}"
loading="lazy">
</picture>
{{ end }}

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB