Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add atom feed to the blog #46

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added blog/modules/ROOT/assets/images/feed_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions blog/modules/ROOT/pages/class-as-a-function.adoc
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
:date: 2024-08-13
:author: Josh Basch
:author-url: https://github.com/HT154
Copy link
Contributor Author

@bioball bioball Jan 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: we can't substitute these attributes in the byline, because it breaks when we embed that byline into index.adoc.

Also, these attributes must be placed before the header.


= Class-as-a-Function Pattern

:use-link-attrs:
Expand Down
6 changes: 6 additions & 0 deletions blog/modules/ROOT/pages/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,9 @@ include::introducing-pkl.adoc[tags=excerpt]
++++
</div>
++++

++++
<div class="blog-feed">
<a href="feed.xml"><img src="_images/feed_icon.png" alt="Atom Feed"/></a>
</div>
++++
3 changes: 3 additions & 0 deletions blog/modules/ROOT/pages/introducing-pkl.adoc
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
:date: 2024-02-01
:author: The Pkl Team

= Introducing Pkl, a programming language for configuration

:use-link-attrs:
Expand Down
4 changes: 4 additions & 0 deletions blog/modules/ROOT/pages/pkl-evolution.adoc
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
:date: 2024-04-29
:author: Dan Chao
:author-url: https://github.com/bioball

= Pkl Evolution

:use-link-attrs:
Expand Down
6 changes: 5 additions & 1 deletion blog/modules/ROOT/pages/testing-in-pkl.adoc
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
:date: 2024-04-09
:author: Dan Chao
:author-url: https://github.com/bioball

= Testing in Pkl

:use-link-attrs:
Expand All @@ -6,7 +10,7 @@
++++
<div class="blog-byline">
++++
by link:https://github.com/bioball[Dan Chao] on April 9th, 2024
by https://github.com/bioball[Dan Chao] on April 9th, 2024
++++
</div>
++++
Expand Down
4 changes: 4 additions & 0 deletions blog/modules/ROOT/pages/using-types.adoc
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
:date: 2024-10-15
:author: Islon Scherer
:author-url: https://github.com/stackoverflow

= Taking types to the next level

:use-link-attrs:
Expand Down
53 changes: 51 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,9 @@
"lodash": "^4.17.21",
"ts-node": "^10.7.0",
"typescript": "^5.3.3"
},
"devDependencies": {
"@types/vinyl": "^2.0.12",
"feed": "^4.2.2"
}
}
90 changes: 90 additions & 0 deletions src/@types/@antora/antora/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Bare minimum typings needed for our bespoke feed extension.
import * as Vinyl from "vinyl"

export type NavigationBuiltEvent = {
contentCatalog: ContentCatalog;
playbook: Playbook;
uiCatalog: UiCatalog;
navigationCatalog: {},
siteCatalog: SiteCatalog;
};

export type Register = (context: Context) => any;
export type Register = (this: Context) => any;

interface SiteCatalog {
addFile(file: { contents: Buffer; out: { path: string } });
}

interface ContentCatalog {
getComponent(id: string): Component
getComponentVeresion(id: string, version: string): Component
getComponents(): Component[]
getComponentsSortedBy(property: string): Component[]
getFiles(): File[]
getPages(filter?: (file: File) => Boolean): File[]
getSiteStartPage(): File?;
addFile(file: any): void;
/**
* Attempts to resolve a string contextual page ID spec to a file in the catalog.
*
* Parses the specified contextual page ID spec into a page ID object, then attempts to lookup a
* file with this page ID in the catalog. If a component is specified, but not a version, the
* latest version of the component stored in the catalog is used. If a page cannot be resolved,
* the search is attempted again for an "alias". If neither a page or alias can be resolved, the
* function returns undefined. If the spec does not match the page ID syntax, this function throws
* an error.
*
* @param spec - The contextual page ID spec (e.g., version@component:module:topic/page.adoc).
* @param ctx - The context to use to qualified the contextual page ID.
*
* @returns {File} The virtual file to which the contextual page ID spec refers, or undefined if the
* file cannot be resolved.
*/
resolvePage(id: string, ctx: object = {}): File?;
}

interface ContentCatalogModel {

}

interface File extends Vinyl {
asciidoc: Asciidoc?
}

interface Asciidoc {
attributes: Record<string, string>;
doctitle?: string;
navtitle?: string;
xreftext?: string;
}

interface Component {
latest: {
displayVersion: string
title: string
version: string
name: string
}
title: string
url: string
}

interface Logger {
info(msg: string): void;
}

interface Context {
getLogger(id: string): Logger;
on(event: "navigationBuilt", handler: (event: NavigationBuiltEvent) => any): void;
}

interface Playbook {
antora: { generator: string; };
asciidoc: { attributes: Record<string, string>; extensions: string[] };
output: { dir: string; clean: boolean }
}

interface UiCatalog {

}
27 changes: 27 additions & 0 deletions src/@types/@antora/page-composer/lib/build-ui-model.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Component, ContentCatalog, ContentCatalogModel } from "@antora/antora";

export interface SiteUiModel {
title: string;
ui: {
url: string;
defaultLayout: string;
};
homeUrl: string;
components: { [string]: Component }
}

export interface BaseUiModel {
antoraVersion: string;
contentCatalog: ContentCatalogModel;
env: Record<string, string>;
site: SiteUiModel;
}

export interface UiModel extends BaseUiModel {
siteRootPath: string;
uiRootPath: string;
}

export function buildSiteUiModel(playbook, contentCatalog): SiteUiModel;

export function buildUiModel(baseUiMode, file, contentCatalog, navigationCatalog): UiModel
52 changes: 52 additions & 0 deletions src/feed/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Register } from "@antora/antora";
import { Feed, FeedOptions } from "feed";
import path from "path";

// @ts-ignore copyright line is not required
const baseFeedOptions: FeedOptions = {
title: "Pkl Blog",
description: "Blog site from the maintainers of the Pkl configuration language",
id: "https://pkl-lang.org/blog/index.html",
link: "https://pkl-lang.org/blog/index.html",
language: "en-US",
favicon: "https://pkl-lang.org/_/img/favicon.svg",
generator: "Pkl Blog"
}

const register: Register = (context) => {
context.on("navigationBuilt", function ({ contentCatalog, playbook, siteCatalog }) {
const feed = new Feed(baseFeedOptions);
let lastUpdated: Date = new Date(0);
for (let page of contentCatalog.getPages((it) => it.basename !== "index.adoc" && it.asciidoc?.attributes["page-component-name"] === "blog")) {
const asciidoc = page.asciidoc!!;
const date = new Date(asciidoc.attributes.date);
if (date > lastUpdated) {
lastUpdated = date;
}
feed.addItem({
title: asciidoc.doctitle!!,
id: asciidoc.attributes.docname,
// @ts-ignore
link: path.join(playbook.site.url, page.out.path),
date: date,
published: date,
author: [
{
name: asciidoc.attributes.author,
link: asciidoc.attributes["author-url"]
}
],
content: page.contents?.toString(),
})
}
feed.options.updated = lastUpdated;
siteCatalog.addFile({
contents: Buffer.from(feed.atom1()),
out: {
path: 'blog/feed.xml'
}
})
});
};

module.exports = { register };
1 change: 1 addition & 0 deletions src/site-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ antora:
extensions:
- require: '@antora/lunr-extension'
index_latest_only: true
- require: 'src/feed/index.ts'
asciidoc:
extensions:
- 'src/highlighter/index.ts'
Expand Down
1 change: 1 addition & 0 deletions src/site-remote.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ antora:
extensions:
- require: '@antora/lunr-extension'
index_latest_only: true
- require: 'src/feed/index.ts'
asciidoc:
extensions:
- 'src/highlighter/index.ts'
Expand Down
8 changes: 8 additions & 0 deletions src/supplemental-ui/css/site-extra.css
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,11 @@ code {
.blog-byline {
color: #5c6370;
}

.blog-feed {
margin-top: 5em;
}

.blog-feed img {
width: 1em;
}
6 changes: 4 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@
"module": "commonjs", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
"baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
"paths": {
"*": ["src/@types/*"]
}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
Expand Down