13 Commits

Author SHA1 Message Date
3d55a7dabe Use individual <a> for each tag/category/etc in post metadata
Fixes #85
2025-08-09 22:34:11 -05:00
67de113bdf Change <header> to be entire top bar
This is more semantically correct.

https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/banner_role
2025-08-09 21:10:57 -05:00
349672bbad Hide comments counter when JavaScript disabled 2025-08-09 20:54:51 -05:00
ec382b2085 Remove unused .view-section rule
It was introduced in 906b6213fd but it
doesn't look like it was actually used for anything.
2025-08-09 20:15:44 -05:00
21f2a91b54 refactor: Move skip to main content CSS into baseof formatting section 2025-08-09 20:15:43 -05:00
0237c496ed refactor: Move components on both list & content pages to different fold 2025-08-09 20:15:38 -05:00
61d5ca29dd Set specific height of code block header
Otherwise it collapses to be too tiny if the copy button is removed.
2025-08-09 03:27:26 -05:00
8bb8720545 Hide code block copy button when JavaScript is disabled 2025-08-09 03:27:05 -05:00
bd8e34a381 Support opengraph structured properties on image and video 2025-08-09 02:53:46 -05:00
62cdcf5b11 Add warning if twitter username is missing
I don't know if the docs are correct, but they seem to say that
twitter:site is required for a card to render at all. Better safe than
sorry.

https://developer.x.com/en/docs/x-for-websites/cards/overview/markup
2025-08-09 02:40:03 -05:00
c9909762d6 Remove use of style attributes on top level comment section elements 2025-08-09 02:20:33 -05:00
cc4af0c385 Add comment explaining why comments.css is not in head 2025-08-09 02:13:15 -05:00
7aeb95a437 Add paragraph around comment section "Enable JavaScript" warning 2025-08-09 01:55:43 -05:00
13 changed files with 154 additions and 109 deletions

View File

@@ -312,6 +312,20 @@ footer p {
margin: 0; margin: 0;
} }
#skip-to-main {
position: absolute;
padding: 8px;
background-color: var(--text-0);
color: var(--background-0);
transform: translateY(-100%);
}
#skip-to-main:focus {
transform: translateY(0%);
}
#main-content:target {
animation: none; /* prevent it from turning yellow */
}
/* }}} */ /* }}} */
/* Top bar formatting {{{ */ /* Top bar formatting {{{ */
@@ -326,7 +340,7 @@ footer p {
* or it will need its hover background to be chopped off on the left */ * or it will need its hover background to be chopped off on the left */
} }
.header { .brand {
flex-grow: 1; flex-grow: 1;
margin: 8px var(--page-margin); margin: 8px var(--page-margin);
font-size: 1.25em; font-size: 1.25em;
@@ -334,7 +348,7 @@ footer p {
align-items: center; align-items: center;
} }
.header a { .brand a {
color: inherit; color: inherit;
font-weight: bold; font-weight: bold;
} }
@@ -360,22 +374,6 @@ footer p {
/* }}} */ /* }}} */
/* Skip to main content {{{ */
#skip-to-main {
position: absolute;
padding: 8px;
background-color: var(--text-0);
color: var(--background-0);
transform: translateY(-100%);
}
#skip-to-main:focus {
transform: translateY(0%);
}
#main-content:target {
animation: none; /* prevent it from turning yellow */
}
/* }}} */
/* Breadcrumb navigation {{{ */ /* Breadcrumb navigation {{{ */
.breadcrumb { .breadcrumb {
@@ -508,6 +506,14 @@ footer p {
margin-top: 10px; margin-top: 10px;
} }
:is(
.page-metadata-section:is(.categories, .tags, .series),
.page-metadata-item.authors
) > a:not(:last-child):after {
color: var(--text-0);
content: ",";
}
.post-media { .post-media {
margin-top: 15px; margin-top: 15px;
} }
@@ -634,10 +640,6 @@ footer p {
margin-bottom: 5px; margin-bottom: 5px;
} }
.view-section {
margin-top: 5px;
}
/* }}} */ /* }}} */
@@ -705,19 +707,6 @@ footer p {
} }
*/ */
/* See also formating */
.see-also {
background-color: var(--background-1);
color: var(--text-1);
padding: 8px 12px;
border-radius: 8px;
margin: 10px 0;
}
.see-also p {
margin: 0;
}
/* Previous and next page buttons {{{ */ /* Previous and next page buttons {{{ */
.prevnext { .prevnext {
@@ -768,6 +757,45 @@ footer p {
/* }}} */ /* }}} */
/* Related posts section {{{ */
/* set the margins on the contents instead of the parent .related-posts
* so that the posts in the list clip off the edge of the screen,
* which makes a more obvious indicator that it's scrollable
*/
.related-posts > hr,
.related-posts > h1 {
margin: var(--page-margin);
}
.related-posts .page {
min-width: 300px;
max-width: 300px;
}
.related-posts .page:first-child {
margin-left: var(--page-margin);
}
.related-posts .page:last-child {
margin-right: var(--page-margin);
}
.related-posts .page-list {
display: flex;
flex-direction: row;
gap: 20px;
overflow-x: auto;
margin-bottom: var(--page-margin);
}
/* }}} */
/* }}} */
/* Content components (can appear both in single and list pages) {{{ */
/* Code & code blocks {{{ */ /* Code & code blocks {{{ */
.code-block { .code-block {
display: flex; display: flex;
@@ -784,10 +812,13 @@ footer p {
padding: 4px 8px; padding: 4px 8px;
border-top-left-radius: 8px; border-top-left-radius: 8px;
border-top-right-radius: 8px; border-top-right-radius: 8px;
height: 2em;
}
.code-block > .code-header > * {
margin: auto 0;
} }
.code-block > .code-header > .code-type { .code-block > .code-header > .code-type {
border-top-left-radius: 8px; border-top-left-radius: 8px;
margin: auto 0;
} }
/* TODO: make the code copy button prettier */ /* TODO: make the code copy button prettier */
.code-block > .code-header > .code-copy-button { .code-block > .code-header > .code-copy-button {
@@ -881,42 +912,21 @@ aside.quote {
/* }}} */ /* }}} */
/* Related posts section {{{ */ /* See also formating */
.see-also {
/* set the margins on the contents instead of the parent .related-posts background-color: var(--background-1);
* so that the posts in the list clip off the edge of the screen, color: var(--text-1);
* which makes a more obvious indicator that it's scrollable padding: 8px 12px;
*/ border-radius: 8px;
margin: 10px 0;
.related-posts > hr,
.related-posts > h1 {
margin: var(--page-margin);
} }
.related-posts .page { .see-also p {
min-width: 300px; margin: 0;
max-width: 300px;
}
.related-posts .page:first-child {
margin-left: var(--page-margin);
}
.related-posts .page:last-child {
margin-right: var(--page-margin);
}
.related-posts .page-list {
display: flex;
flex-direction: row;
gap: 20px;
overflow-x: auto;
margin-bottom: var(--page-margin);
} }
/* }}} */ /* }}} */
/* }}} */
/* @media specializations {{{ */ /* @media specializations {{{ */

View File

@@ -1,3 +1,14 @@
.comments > h2 {
margin-bottom: 0;
}
.comments .email-address-notice {
margin: 0;
font-size: smaller;
}
.comments .enable-javascript-notice {
font-style: italic;
}
/* Isso styling */ /* Isso styling */
h4.isso-thread-heading { h4.isso-thread-heading {
color: var(--text-0); color: var(--text-0);

4
assets/css/noscript.css Normal file
View File

@@ -0,0 +1,4 @@
.page-meta-comments-counter,
.code-copy-button {
display: none;
}

View File

@@ -1,15 +1,20 @@
{{/* put comments CSS here instead of in <head> so that it doesn't get
* loaded unnecessarily on regular pages
*/}}
{{ with resources.Get "css/comments.css" | fingerprint "sha512" }} {{ with resources.Get "css/comments.css" | fingerprint "sha512" }}
<link rel="stylesheet" type="text/css" href="{{ .Permalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous"> <link rel="stylesheet" type="text/css" href="{{ .Permalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
{{ end }} {{ end }}
<h2 style="margin-bottom: 0;">Comments</h2> <h2>Comments</h2>
<p style="margin: 0; font-size: smaller;"> <p class="email-address-notice">
If you provide an email address, you can enable notifications for If you provide an email address, you can enable notifications for
replies to your comment. It will not be shown publicly. replies to your comment. It will not be shown publicly.
</p> </p>
<noscript> <noscript>
<i>Enable JavaScript to see the comment section.</i> <p class="enable-javascript-notice">
Enable JavaScript to see the comment section.
</p>
</noscript> </noscript>
<section id="isso-thread" data-title="{{ .Title }}"></section> <section id="isso-thread" data-title="{{ .Title }}"></section>

View File

@@ -6,6 +6,12 @@
{{ with resources.Get "css/bobastyle.css" | fingerprint "sha512" }} {{ with resources.Get "css/bobastyle.css" | fingerprint "sha512" }}
<link rel="stylesheet" type="text/css" href="{{ .Permalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous"> <link rel="stylesheet" type="text/css" href="{{ .Permalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
{{ end }} {{ end }}
{{ with resources.Get "css/noscript.css" | fingerprint "sha512" }}
<noscript>
<link rel="stylesheet" type="text/css" href="{{ .Permalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous">
</noscript>
{{ end }}
{{ with resources.Get "css/syntax.css" | fingerprint "sha512" }} {{ with resources.Get "css/syntax.css" | fingerprint "sha512" }}
<link rel="stylesheet" type="text/css" href="{{ .Permalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous" media="print" onload="this.media='all'"> <link rel="stylesheet" type="text/css" href="{{ .Permalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous" media="print" onload="this.media='all'">
{{ end }} {{ end }}

View File

@@ -1,16 +1,9 @@
{{ with .Params.authors }} {{ with .GetTerms "authors" }}
<span class="page-metadata-item" data-pagefind-meta="authors" aria-label="{{ i18n "aria_post_meta_authors" }}"> <span class="page-metadata-item authors" aria-label="{{ i18n "aria_post_meta_authors" }}">
{{ partial "icon.html" "user-circle" }} {{ partial "icon.html" "user-circle" }}
{{ if index $.Site.Taxonomies "authors" }} {{ range . }}
{{ $authors := slice }} <a href="{{ .Permalink }}" data-pagefind-filter="author">{{ .LinkTitle }}</a>
{{ range . }}
{{ $url := (printf "authors/%s" (. | anchorize)) | absLangURL }}
{{ $authors = $authors | append (printf `<a href="%s">%s</a>` $url .) }}
{{ end }}
{{ delimit $authors ", " | safeHTML }}
{{ else }}
{{ delimit . ", " }}
{{ end }} {{ end }}
</span> </span>
{{ end }} {{ end }}

View File

@@ -4,8 +4,10 @@
{{ $categories = $categories | append (printf `<a href="%s">%s</a>` .Permalink .LinkTitle) }} {{ $categories = $categories | append (printf `<a href="%s">%s</a>` .Permalink .LinkTitle) }}
{{ end }} {{ end }}
<div class="page-metadata-section categories" data-pagefind-meta="categories" aria-label="{{ i18n "aria_post_meta_categories" }}"> <div class="page-metadata-section categories" aria-label="{{ i18n "aria_post_meta_categories" }}">
{{ partial "icon.html" "folder" }} {{ partial "icon.html" "folder" }}
{{ delimit $categories ", " | safeHTML }} {{ range . }}
<a href="{{ .Permalink }}" data-pagefind-filter="category">{{ .LinkTitle }}</a>
{{ end }}
</div> </div>
{{ end }} {{ end }}

View File

@@ -1,4 +1,4 @@
<span class="page-metadata-item" aria-label="comments counter"> <span class="page-metadata-item page-meta-comments-counter" aria-label="comments counter">
{{ partial "icon.html" "message" }} {{ partial "icon.html" "message" }}
{{/* TODO: figure out if there's a nicer way to generate this URL {{/* TODO: figure out if there's a nicer way to generate this URL
* the current issue is that we can't use RelRef, since content view means that we don't * the current issue is that we can't use RelRef, since content view means that we don't

View File

@@ -1,11 +1,8 @@
{{ with (.GetTerms "series") }} {{ with (.GetTerms "series") }}
{{ $series := slice }} <div class="page-metadata-section series" aria-label="{{ i18n "aria_post_meta_series" }}">
{{ range . }}
{{ $series = $series | append (printf `<a href="%s">%s</a>` .Permalink .LinkTitle) }}
{{ end }}
<div class="page-metadata-section series" data-pagefind-meta="series" aria-label="{{ i18n "aria_post_meta_series" }}">
{{ partial "icon.html" "files" }} {{ partial "icon.html" "files" }}
{{ delimit $series ", " | safeHTML }} {{ range . }}
<a href="{{ .Permalink }}" data-pagefind-filter="series">{{ .LinkTitle }}</a>
{{ end }}
</div> </div>
{{ end }} {{ end }}

View File

@@ -1,11 +1,10 @@
{{ with (.GetTerms "tags") }} {{ with (.GetTerms "tags") }}
{{ $tags := slice }} {{ $tags := slice }}
{{ range . }}
{{ $tags = $tags | append (printf `<a href="%s">%s</a>` .Permalink .LinkTitle) }}
{{ end }}
<div class="page-metadata-section tags" data-pagefind-meta="tags" aria-label="{{ i18n "aria_post_meta_tags" }}"> <div class="page-metadata-section tags" aria-label="{{ i18n "aria_post_meta_tags" }}">
{{ partial "icon.html" "tag" }} {{ partial "icon.html" "tag" }}
{{ delimit $tags ", " | safeHTML }} {{ range . }}
<a href="{{ .Permalink }}" data-pagefind-filter="tag">{{ .LinkTitle }}</a>
{{ end }}
</div> </div>
{{ end }} {{ end }}

View File

@@ -3,16 +3,6 @@
<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 }}">
{{ $images := $.Resources.ByType "image" }}
{{ $featured := $images.GetMatch "*feature*" }}
{{ if not $featured }}
{{ $featured = $images.GetMatch "{*cover*,*thumbnail*}" }}
{{ end }}
{{ with $featured }}
<meta property="og:image" content="{{ $featured.Permalink }}">
{{ end }}
{{ with .Section }} {{ with .Section }}
<meta property="article:section" content="{{ . }}"> <meta property="article:section" content="{{ . }}">
{{ end }} {{ end }}
@@ -37,12 +27,38 @@
<meta property="og:site_name" content="{{ . }}"> <meta property="og:site_name" content="{{ . }}">
{{ end }} {{ end }}
{{ $images := $.Resources.ByType "image" }}
{{ $featured := $images.GetMatch "*feature*" }}
{{ if not $featured }}
{{ $featured = $images.GetMatch "{*cover*,*thumbnail*}" }}
{{ end }}
{{ with $featured }}
<meta property="og:image" content="{{ $featured.Permalink }}">
{{ with .Params.alt }}
<meta property="og:image:alt" content="{{ . }}">
{{ end }}
{{ with .MediaType }}
<meta property="og:image:type" content="{{ . }}">
{{ end }}
{{ with .Width }}
<meta property="og:image:width" content="{{ . }}">
{{ end }}
{{ with .Height }}
<meta property="og:image:height" content="{{ . }}">
{{ end }}
{{ end }}
{{ $videos := $.Resources.ByType "video" }} {{ $videos := $.Resources.ByType "video" }}
{{ $featured_video := $videos.GetMatch "*feature*" }} {{ $featured_video := $videos.GetMatch "*feature*" }}
{{ if not $featured_video }} {{ if not $featured_video }}
{{ $featured_video = $videos.GetMatch "{*cover*,*thumbnail*}" }} {{ $featured_video = $videos.GetMatch "{*cover*,*thumbnail*}" }}
{{ end }} {{ end }}
{{ with $featured_video }} {{ with $featured_video }}
<meta property="og:video" content="{{ $featured_video.Permalink | absURL }}"> <meta property="og:video" content="{{ $featured_video.Permalink | absURL }}">
{{ with .MediaType }}
<meta property="og:video:type" content="{{ . }}">
{{ end }}
{{ end }} {{ end }}

View File

@@ -31,6 +31,8 @@
*/}} */}}
{{ with .Site.Params.social.twitter }} {{ with .Site.Params.social.twitter }}
<meta name="twitter:site" content="@{{ . }}"> <meta name="twitter:site" content="@{{ . }}">
{{ else }}
{{ errorf "a twitter username is required for twitter cards to work" }}
{{ end }} {{ end }}
{{ with .GetTerms "authors" }} {{ with .GetTerms "authors" }}
{{ range . }} {{ range . }}

View File

@@ -1,9 +1,9 @@
<div class="top"> <header class="top">
<header class="header"> <div class="brand">
<a href="{{ .Site.Home.Permalink | absLangURL }}"> <a href="{{ .Site.Home.Permalink | absLangURL }}">
{{ .Site.Title | markdownify }} {{ .Site.Title | markdownify }}
</a> </a>
</header> </div>
<nav class="navbar" aria-label="{{ i18n "aria_navbar" }}"> <nav class="navbar" aria-label="{{ i18n "aria_navbar" }}">
{{ with .Site.Home }} {{ with .Site.Home }}
@@ -21,4 +21,4 @@
href="{{ .URL }}">{{ .Name }}</a> href="{{ .URL }}">{{ .Name }}</a>
{{ end }} {{ end }}
</nav> </nav>
</div> </header>