atom feed generator, titles

This commit is contained in:
Evert Prants 2022-10-16 15:50:21 +03:00
parent b6b84cfa33
commit 4dfcf1b408
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
14 changed files with 143 additions and 16 deletions

View File

@ -1,7 +1,7 @@
.blog { .blog {
width: 100%; width: 100%;
min-height: 100vh; min-height: 100vh;
background-color: rgb(241, 241, 241); background-color: #eee;
a { a {
color: #258fb8; color: #258fb8;
@ -131,17 +131,16 @@
ul, ul,
ol, ol,
dl { dl {
margin: 0 20px; margin: 1.6em 20px;
line-height: 1.6em; line-height: 1.6em;
padding: 0; padding: 0;
margin-top: 1.6em;
margin-bottom: 1.6em;
} }
} }
&__inner { &__inner {
overflow: hidden; overflow: hidden;
background-color: #fff; background-color: #fff;
box-shadow: 1px 2px 3px #ddd;
} }
&__meta { &__meta {
@ -208,7 +207,7 @@
} }
a { a {
color: #258fb8; color: #006891;
} }
ul { ul {
@ -225,6 +224,7 @@
&-archives { &-archives {
margin: 50px 0; margin: 50px 0;
&__year { &__year {
margin-bottom: 1em; margin-bottom: 1em;
font-size: 0.85em; font-size: 0.85em;
@ -245,6 +245,10 @@
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
gap: 1.5rem; gap: 1.5rem;
@media all and (max-width: 567px) {
grid-template-columns: 1fr;
}
} }
&__time { &__time {
@ -259,15 +263,12 @@
&__post { &__post {
padding: 20px; padding: 20px;
background-color: #fff; background-color: #fff;
box-shadow: 1px 2px 3px #ddd;
header { header {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
h1 {
margin-top: auto;
}
} }
} }
} }

View File

@ -8,6 +8,13 @@
<Meta property="og:locale" content="en_US" /> <Meta property="og:locale" content="en_US" />
<Meta property="article:author" content="Evert Prants" /> <Meta property="article:author" content="Evert Prants" />
<Meta name="twitter:card" content="summary" /> <Meta name="twitter:card" content="summary" />
<Link
rel="alternate"
href="/blog/atom.xml"
title="Evert's Blog"
type="application/atom+xml"
/>
<Title>Evert's Blog | lunasqu.ee</Title>
</Head> </Head>
<header class="blog__header"> <header class="blog__header">
<h1><NuxtLink to="/blog">Blog</NuxtLink></h1> <h1><NuxtLink to="/blog">Blog</NuxtLink></h1>

View File

@ -107,6 +107,8 @@ export async function getTags(): Promise<BlogPostTag[]> {
} }
} }
obj.sort((a, b) => a.name.localeCompare(b.name, 'en'));
return obj; return obj;
} }

View File

@ -37,7 +37,7 @@ export default defineNuxtConfig({
hooks: { hooks: {
async 'nitro:config'(config) { async 'nitro:config'(config) {
const routes = await generatePaths('/blog/'); const routes = await generatePaths('/blog/');
config.prerender.routes.push(...routes); config.prerender.routes.push(...routes, '/blog/atom.xml');
}, },
}, },
}); });

49
package-lock.json generated
View File

@ -6,6 +6,7 @@
"": { "": {
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"feed": "^4.2.2",
"highlight.js": "^11.6.0", "highlight.js": "^11.6.0",
"sass": "^1.55.0" "sass": "^1.55.0"
}, },
@ -3320,6 +3321,17 @@
"reusify": "^1.0.4" "reusify": "^1.0.4"
} }
}, },
"node_modules/feed": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz",
"integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==",
"dependencies": {
"xml-js": "^1.6.11"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/fetch-blob": { "node_modules/fetch-blob": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
@ -6250,6 +6262,11 @@
"node": ">=12.0.0" "node": ">=12.0.0"
} }
}, },
"node_modules/sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"node_modules/scule": { "node_modules/scule": {
"version": "0.3.2", "version": "0.3.2",
"resolved": "https://registry.npmjs.org/scule/-/scule-0.3.2.tgz", "resolved": "https://registry.npmjs.org/scule/-/scule-0.3.2.tgz",
@ -7494,6 +7511,17 @@
} }
} }
}, },
"node_modules/xml-js": {
"version": "1.6.11",
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
"integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
"dependencies": {
"sax": "^1.2.4"
},
"bin": {
"xml-js": "bin/cli.js"
}
},
"node_modules/xxhashjs": { "node_modules/xxhashjs": {
"version": "0.2.2", "version": "0.2.2",
"resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz",
@ -10029,6 +10057,14 @@
"reusify": "^1.0.4" "reusify": "^1.0.4"
} }
}, },
"feed": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/feed/-/feed-4.2.2.tgz",
"integrity": "sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==",
"requires": {
"xml-js": "^1.6.11"
}
},
"fetch-blob": { "fetch-blob": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
@ -12165,6 +12201,11 @@
"source-map-js": ">=0.6.2 <2.0.0" "source-map-js": ">=0.6.2 <2.0.0"
} }
}, },
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"scule": { "scule": {
"version": "0.3.2", "version": "0.3.2",
"resolved": "https://registry.npmjs.org/scule/-/scule-0.3.2.tgz", "resolved": "https://registry.npmjs.org/scule/-/scule-0.3.2.tgz",
@ -13114,6 +13155,14 @@
"dev": true, "dev": true,
"requires": {} "requires": {}
}, },
"xml-js": {
"version": "1.6.11",
"resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz",
"integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==",
"requires": {
"sax": "^1.2.4"
}
},
"xxhashjs": { "xxhashjs": {
"version": "0.2.2", "version": "0.2.2",
"resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz",

View File

@ -15,6 +15,7 @@
"yaml": "^2.1.3" "yaml": "^2.1.3"
}, },
"dependencies": { "dependencies": {
"feed": "^4.2.2",
"highlight.js": "^11.6.0", "highlight.js": "^11.6.0",
"sass": "^1.55.0" "sass": "^1.55.0"
} }

View File

@ -16,6 +16,7 @@
<Meta property="article:author" content="Evert Prants" /> <Meta property="article:author" content="Evert Prants" />
<Meta v-for="tag in post.tags" property="article:tag" :content="tag" /> <Meta v-for="tag in post.tags" property="article:tag" :content="tag" />
<Meta name="twitter:card" content="summary" /> <Meta name="twitter:card" content="summary" />
<Title>{{ post.title }} | Evert's Blog | lunasqu.ee</Title>
</Head> </Head>
<BlogPost :post="post" :detail="true" /> <BlogPost :post="post" :detail="true" />

View File

@ -1,5 +1,13 @@
<template> <template>
<NuxtLayout name="blog"> <NuxtLayout name="blog">
<Head>
<Title
>Archive: {{ route.params.year }}/{{ route.params.month }}/{{
route.params.day
}}
| Evert's Blog | lunasqu.ee</Title
>
</Head>
<BlogArchive :posts="posts" /> <BlogArchive :posts="posts" />
</NuxtLayout> </NuxtLayout>
</template> </template>
@ -14,7 +22,6 @@ const { data: posts } = await useFetch<BlogPost[]>(`/api/blog`, {
year: route.params.year, year: route.params.year,
month: route.params.month, month: route.params.month,
day: route.params.day, day: route.params.day,
body: false,
render: false, render: false,
}, },
}); });

View File

@ -1,5 +1,11 @@
<template> <template>
<NuxtLayout name="blog"> <NuxtLayout name="blog">
<Head>
<Title
>Archive: {{ route.params.year }}/{{ route.params.month }} | Evert's
Blog | lunasqu.ee</Title
>
</Head>
<BlogArchive :posts="posts" /> <BlogArchive :posts="posts" />
</NuxtLayout> </NuxtLayout>
</template> </template>
@ -13,7 +19,6 @@ const { data: posts } = await useFetch<BlogPost[]>(`/api/blog`, {
params: { params: {
year: route.params.year, year: route.params.year,
month: route.params.month, month: route.params.month,
body: false,
render: false, render: false,
}, },
}); });

View File

@ -1,5 +1,10 @@
<template> <template>
<NuxtLayout name="blog"> <NuxtLayout name="blog">
<Head>
<Title
>Archive: {{ route.params.year }} | Evert's Blog | lunasqu.ee</Title
>
</Head>
<BlogArchive :posts="posts" /> <BlogArchive :posts="posts" />
</NuxtLayout> </NuxtLayout>
</template> </template>
@ -12,7 +17,6 @@ const { data: posts } = await useFetch<BlogPost[]>(`/api/blog`, {
key: `${route.params.year}-archive-page`, key: `${route.params.year}-archive-page`,
params: { params: {
year: route.params.year, year: route.params.year,
body: false,
render: false, render: false,
}, },
}); });

View File

@ -1,5 +1,8 @@
<template> <template>
<NuxtLayout name="blog"> <NuxtLayout name="blog">
<Head>
<Title>Archive | Evert's Blog | lunasqu.ee</Title>
</Head>
<BlogArchive :posts="posts" /> <BlogArchive :posts="posts" />
</NuxtLayout> </NuxtLayout>
</template> </template>
@ -10,7 +13,6 @@ import type { BlogPost } from '~~/lib/types/post';
const { data: posts } = await useFetch<BlogPost[]>(`/api/blog`, { const { data: posts } = await useFetch<BlogPost[]>(`/api/blog`, {
key: `blog-archive`, key: `blog-archive`,
params: { params: {
body: false,
render: false, render: false,
}, },
}); });

View File

@ -1,5 +1,8 @@
<template> <template>
<NuxtLayout name="blog"> <NuxtLayout name="blog">
<Head>
<Title>Tag: {{ route.params.tag }} | Evert's Blog | lunasqu.ee</Title>
</Head>
<BlogArchive :posts="posts" /> <BlogArchive :posts="posts" />
</NuxtLayout> </NuxtLayout>
</template> </template>
@ -12,7 +15,6 @@ const { data: posts } = await useFetch<BlogPost[]>(`/api/blog`, {
key: `${route.params.tag}-tag-page`, key: `${route.params.tag}-tag-page`,
params: { params: {
tag: route.params.tag, tag: route.params.tag,
body: false,
render: false, render: false,
}, },
}); });

View File

@ -35,6 +35,6 @@ export default defineEventHandler(async (event) => {
return readBlogPosts( return readBlogPosts(
include, include,
query.render !== 'false', query.render !== 'false',
query.body !== 'false' query.body === 'true'
); );
}); });

View File

@ -0,0 +1,46 @@
import { Feed } from 'feed';
import { readBlogPosts } from '~~/lib/blog/read-posts';
const BASE_URL = 'https://lunasqu.ee/blog';
export default defineEventHandler(async (event) => {
const posts = await readBlogPosts(undefined, true, false);
const feed = new Feed({
title: "Evert's Blog",
description: 'Projects and Tutorials',
id: BASE_URL,
link: BASE_URL,
copyright: 'Evert "Diamond" Prants 2022',
language: 'en',
updated: new Date(posts[0].date),
generator: 'https://gitlab.icynet.eu/evert/lunasqu.ee-nuxt',
feedLinks: {
atom: `${BASE_URL}/atom.xml`,
},
});
posts.forEach((post) => {
const description = post.html
.replace(/<[^>]*>?/gm, '')
.replace('\n', ' ')
.substring(0, 240);
feed.addItem({
title: post.title,
id: `${BASE_URL}/${post.fullSlug}`,
link: `${BASE_URL}/${post.fullSlug}`,
description,
content: post.html,
date: new Date(post.date),
published: new Date(post.date),
category: post.tags.map((tag) => ({
term: tag,
scheme: `${BASE_URL}/tags/${tag}`,
})),
});
});
appendResponseHeader(event, 'Content-Type', 'text/xml');
return feed.atom1();
});