Skip to content

Commit 3b31eaa

Browse files
committed
Series concept added. Small refactorings and css updates.
1 parent da68af1 commit 3b31eaa

File tree

15 files changed

+300
-68
lines changed

15 files changed

+300
-68
lines changed

_config/collections.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
export default function(eleventyConfig) {
2+
eleventyConfig.addCollection("series", function(collection) {
3+
const posts = collection.getAll();
4+
5+
// this will store the mapping from series to lists of posts; it can be a
6+
// regular object if you prefer
7+
const mapping = new Map();
8+
9+
// loop over the posts
10+
for (const post of posts) {
11+
12+
// ignore anything with no series data
13+
if (post.data.series === undefined) {
14+
continue;
15+
}
16+
17+
for(var key of post.data.series)
18+
{
19+
if(!mapping.has(key))
20+
{
21+
mapping.set(key, []);
22+
}
23+
mapping.get(key).push(post);
24+
}
25+
}
26+
27+
for(const [key, value] of mapping.entries())
28+
{
29+
value.sort((a, b) => a.date - b.date);
30+
}
31+
32+
return Object.fromEntries(mapping);
33+
});
34+
35+
eleventyConfig.addCollection("tags", function(collection) {
36+
const excludedTags = ["posts", "all"];
37+
const posts = collection.getAll();
38+
39+
// this will store the mapping from series to lists of posts; it can be a
40+
// regular object if you prefer
41+
const mapping = new Map();
42+
43+
// loop over the posts
44+
for (const post of posts) {
45+
46+
// ignore anything with no series data
47+
if (post.data.tags === undefined) {
48+
continue;
49+
}
50+
51+
for(var key of post.data.tags)
52+
{
53+
if(excludedTags.indexOf(key) !== -1) continue;
54+
55+
if(!mapping.has(key))
56+
{
57+
mapping.set(key, []);
58+
}
59+
mapping.get(key).push(post);
60+
}
61+
}
62+
63+
for(const [key, value] of mapping.entries())
64+
{
65+
value.sort((a, b) => a.date - b.date);
66+
}
67+
68+
return Object.fromEntries(mapping);
69+
});
70+
}

_includes/layouts/post.njk

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,20 @@ article {
1111

1212
.links-nextprev {
1313
display: flex;
14+
gap: 1rem;
1415
padding: 0;
1516
margin: 0;
1617
list-style: none;
1718
}
1819
.links-nextprev li {
1920
width: 50%;
21+
padding: 0.5rem;
22+
}
23+
.links-nextprev li.links-nextprev-prev,
24+
.links-nextprev li.links-nextprev-next {
25+
background-color: var(--bg-color-secondary);
26+
box-shadow: 2px 2px 4px var(--shadow-color);
27+
transition: background-color 0.3s;
2028
}
2129
.links-nextprev-next {
2230
text-align: right;
@@ -27,6 +35,10 @@ h1.post-title {
2735
margin-bottom: 1rem;
2836
}
2937

38+
#giscus-comments {
39+
margin-top: 1rem;
40+
}
41+
3042
{% endcss %}
3143

3244
<article>
@@ -50,12 +62,34 @@ h1.post-title {
5062
{% set nextPost = collections.posts | getNextCollectionItem %}
5163
{% if nextPost or previousPost %}
5264
<ul class="links-nextprev">
53-
<li class="links-nextprev-prev">{% if previousPost %}← Previous<br> <a href="{{ previousPost.url }}">{{ previousPost.data.title }}</a>{% endif %}</li>
54-
<li class="links-nextprev-next">{% if nextPost %}Next →<br><a href="{{ nextPost.url }}">{{ nextPost.data.title }}</a>{% endif %}</li>
65+
{% if previousPost %}
66+
<li class="links-nextprev-prev">
67+
<a href="{{ previousPost.url }}">
68+
<img eleventy:ignore src="{{ previousPost.data.imageUrl }}" alt="" /><br>
69+
{{ previousPost.data.title }}
70+
</a>
71+
<br>← Previous
72+
{% else %}
73+
<li>
74+
{% endif %}
75+
</li>
76+
{% if nextPost %}
77+
<li class="links-nextprev-next">
78+
<a href="{{ nextPost.url }}">
79+
<img eleventy:ignore src="{{ nextPost.data.imageUrl }}" alt="" /><br>
80+
{{ nextPost.data.title }}
81+
</a>
82+
<br>Next →
83+
{% else %}
84+
<li>
85+
{% endif %}
86+
</li>
5587
</ul>
5688
{% endif %}
5789
{% endif %}
5890

91+
{% include "./../partials/series.njk" %}
92+
5993
{% if metadata.githubComments.repo %}
6094
<div id="giscus-comments"></div>
6195
<script>

_includes/partials/footer.njk

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,15 @@ footer {
55
margin-top: 1.5rem;
66
padding: 0.5em;
77
background-color: var(--bg-color-secondary);
8-
transition: background-color 0.3s, color 0.3s;
8+
transition: background-color 0.3s;
99
box-shadow: 0 -2px 4px var(--shadow-color);
1010
z-index: 1000;
1111
}
12+
@media(max-height: 480px) {
13+
footer {
14+
position: relative;
15+
}
16+
}
1217

1318
.footer-container {
1419
display: flex;

_includes/partials/header.njk

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ header {
99

1010
z-index: 1000;
1111
}
12+
@media(max-height: 480px) {
13+
header {
14+
position: relative;
15+
}
16+
}
17+
1218
header:after {
1319
content: "";
1420
display: table;

_includes/partials/post-meta.njk

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{% css %}
22
.post-metadata {
3-
display: inline-flex;
3+
display: flex;
44
flex-wrap: wrap;
55
list-style: none;
66
padding: 0;
77
margin: 0;
88
gap: 1rem 2rem;
99
}
1010

11-
.post-metadata .tag {
11+
.post-metadata .tag, .post-metadata .serie {
1212
border: 1px solid var(--border-color);
1313
border-radius: 4px;
1414
background-color: var(--bg-color-secondary);
@@ -33,6 +33,15 @@
3333
<i class="fa-regular fa-clock"></i>
3434
{{ post.templateContent | striptags | wordcount | readingTime }}
3535
</div>
36+
<div>
37+
{% if post.data.series.length > 0 %}
38+
<i class="fa-solid fa-rectangle-list"></i>
39+
{%- for serie in post.data.series %}
40+
{%- set serieUrl %}/series/{{ serie | slugify }}/{% endset %}
41+
<span class="serie"><a href="{{ serieUrl }}">{{ serie }}</a></span>
42+
{%- endfor %}
43+
{% endif %}
44+
</div>
3645
<div>
3746
{% set tags = post.data.tags | filterTagList %}
3847
{% if tags.length > 0 %}

_includes/partials/series.njk

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{% css %}
2+
.series {
3+
display: grid;
4+
grid-gap: 1rem;
5+
grid-template-columns: 1fr 1fr 1fr;
6+
margin-top: 1rem;
7+
}
8+
@media(max-width: 1024px) {
9+
.series {
10+
grid-template-columns: 1fr 1fr;
11+
}
12+
}
13+
@media(max-width: 480px) {
14+
.series {
15+
grid-template-columns: 100%;
16+
}
17+
}
18+
.series h3 {
19+
grid-column: 1 / -1;
20+
margin: 0
21+
}
22+
.series-post {
23+
padding: 0.5rem;
24+
background-color: var(--bg-color-secondary);
25+
box-shadow: 2px 2px 4px var(--shadow-color);
26+
transition: background-color 0.3s;
27+
}
28+
{% endcss %}
29+
30+
<div class="series">
31+
{% for k, v in collections.series %}
32+
{% if v.length > 1 and k in series %}
33+
{% set serieUrl %}/series/{{ k | slugify }}/{% endset %}
34+
<h3>Latest posts in the <a href="{{ serieUrl }}">{{ k }}</a> series</h3>
35+
{% for seriePost in v.slice(-3) | reverse %}
36+
<div class="series-post">
37+
<a href="{{ seriePost.url }}">
38+
<img eleventy:ignore src="{{seriePost.data.imageUrl }}" alt="{{ seriePost.data.title }}" class="series-post-image" />
39+
{{ seriePost.data.title }}
40+
</a>
41+
<br />
42+
{{ seriePost.data.date | readableDate }}
43+
</div>
44+
{% endfor %}
45+
{% endif %}
46+
{% endfor %}
47+
</div>

content/about.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
eleventyNavigation:
33
key: "About"
4-
order: 3
4+
order: 5
55
aside: true
66
---
77
# About me

content/blog.njk renamed to content/archive.njk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
eleventyNavigation:
33
key: "Archive"
4-
order: 2
4+
order: 4
55
aside: true
66
---
77
{%- css %}

content/blog/blog.11tydata.js

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,60 @@
1+
import slugify from "slugify"; // Import slugify
2+
import path from 'node:path';
3+
import Image from "@11ty/eleventy-img";
4+
15
export default {
26
tags: [
37
"posts"
48
],
59
"layout": "layouts/post.njk",
6-
"aside": true
10+
"aside": true,
11+
"eleventyComputed": {
12+
"imageUrl": data => headerImageUrl(data),
13+
"permalink": data => blogUrl(data),
14+
},
715
};
16+
17+
async function headerImageUrl(data) {
18+
19+
if(!data.image || !data.page.url)
20+
{
21+
return null;
22+
}
23+
24+
const inputDir = path.dirname(data.page.inputPath);
25+
const imagePath = path.resolve(inputDir, data.image);
26+
27+
const imageOptions = {
28+
formats: ["png"],
29+
urlPath: data.page.url,
30+
outputDir: path.dirname(data.page.outputPath),
31+
filenameFormat: function (hash, src, width, format) {
32+
return `${hash}-${width}.${format}`;
33+
},
34+
cacheOptions: {
35+
duration: "1w"
36+
}
37+
};
38+
39+
const img = await Image(imagePath, imageOptions);
40+
41+
// Get the generated image URL
42+
const formatData = img[imageOptions.formats[0]];
43+
if (!formatData || !formatData[0]) {
44+
throw new Error(`Image processing failed for ${src}`);
45+
}
46+
47+
return formatData[0].url; // Return the URL of the processed image
48+
}
49+
50+
function blogUrl(data) {
51+
if (!data.permalink) {
52+
// Automatically slugify titles for URLs if no permalink is explicitly set
53+
var year = data.date
54+
? new Date(data.date).getFullYear() + "/"
55+
: "";
56+
var name = slugify(data.title ?? data.page.fileSlug, { lower: true, strict: true }) + "/";
57+
return `/${year}${name}`;
58+
}
59+
return data.permalink; // Use the explicitly set permalink if available
60+
}

content/series-pages.njk

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---js
2+
// <script>
3+
const pagination = {
4+
data: "collections.series",
5+
size: 1,
6+
alias: "serie",
7+
// addAllPagesToCollections: true,
8+
};
9+
10+
const eleventyExcludeFromCollections = true;
11+
12+
const eleventyComputed = {
13+
title: "Series '{{ serie }}'",
14+
permalink: function(data) {
15+
return `/series/${this.slugify(data.serie)}/`;
16+
}
17+
};
18+
// </script>
19+
---
20+
{% css %}
21+
.posts {
22+
display: grid;
23+
grid-gap: 1rem;
24+
grid-template-columns: 1fr 1fr;
25+
}
26+
@media(max-width: 1024px) {
27+
.posts {
28+
grid-template-columns: 100%;
29+
}
30+
}
31+
{% endcss %}
32+
33+
<h1>Series “{{ serie }}”</h1>
34+
35+
<div class="posts">
36+
{% for post in collections.series[serie] | reverse %}
37+
{% include "partials/post-card.njk" %}
38+
{% endfor %}
39+
</div>
40+
41+
<p>See <a href="series.njk">all series</a>.</p>

0 commit comments

Comments
 (0)