-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: adds an RSS feed to the generated blog
- Loading branch information
Showing
18 changed files
with
364 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import type { StarlightUserConfig } from '@astrojs/starlight/types' | ||
|
||
export function getDefaultLocale(starlightConfig: StarlightUserConfig) { | ||
let defaultLocale = 'en' | ||
const defaultLocaleKey = starlightConfig.defaultLocale | ||
|
||
if (starlightConfig.locales) { | ||
defaultLocale = | ||
defaultLocaleKey && defaultLocaleKey !== 'root' | ||
? starlightConfig.locales[defaultLocaleKey]?.lang ?? defaultLocaleKey | ||
: starlightConfig.locales['root']?.lang ?? defaultLocale | ||
} | ||
|
||
return defaultLocale | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Marked } from 'marked' | ||
import markedPlaintify from 'marked-plaintify' | ||
import { transform } from 'ultrahtml' | ||
import sanitize from 'ultrahtml/transformers/sanitize' | ||
|
||
const markedMd = new Marked({ gfm: true }) | ||
const markedText = new Marked({ gfm: true }, markedPlaintify()) | ||
|
||
export async function stripMarkdown(markdown: string) { | ||
return await markedText.parse(markdown) | ||
} | ||
|
||
export async function renderMarkdownToHTML(markdown: string) { | ||
const content = await markedMd.parse(markdown) | ||
|
||
return transform(content, [sanitize()]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import type { RSSOptions } from '@astrojs/rss' | ||
import config from 'virtual:starlight-blog-config' | ||
import context from 'virtual:starlight-blog-context' | ||
|
||
import { getBlogEntries, type StarlightBlogEntry } from './content' | ||
import { renderMarkdownToHTML, stripMarkdown } from './markdown' | ||
import { getPathWithBase } from './page' | ||
|
||
export function getRSSStaticPaths() { | ||
return [{ params: { prefix: config.prefix } }] | ||
} | ||
|
||
export async function getRSSOptions(site: URL | undefined) { | ||
const entries = await getBlogEntries() | ||
entries.splice(20) | ||
|
||
const options: RSSOptions = { | ||
title: getRSSTitle(), | ||
description: context.description ?? '', | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- The route is only injected if `site` is defined in the user Astro config. | ||
site: site!, | ||
items: await Promise.all( | ||
entries.map(async (entry) => { | ||
return { | ||
title: entry.data.title, | ||
link: getPathWithBase(`/${entry.slug}`), | ||
pubDate: entry.data.date, | ||
categories: entry.data.tags, | ||
description: await getRSSDescription(entry), | ||
content: await getRSSContent(entry), | ||
} | ||
}), | ||
), | ||
customData: `<language>${context.defaultLocale}</language>`, | ||
} | ||
|
||
if (context.trailingSlash !== 'ignore') { | ||
options.trailingSlash = context.trailingSlash === 'always' | ||
} | ||
|
||
return options | ||
} | ||
|
||
function getRSSTitle() { | ||
let title = (typeof context.title === 'string' ? context.title : context.title[context.defaultLocale]) ?? '' | ||
|
||
if (title.length > 0) { | ||
title += ` ${context.titleDelimiter ?? '|'} ` | ||
} | ||
|
||
title += config.title | ||
|
||
return title | ||
} | ||
|
||
function getRSSDescription(entry: StarlightBlogEntry): Promise<string> | undefined { | ||
if (!entry.data.excerpt) return | ||
|
||
return stripMarkdown(entry.data.excerpt) | ||
} | ||
|
||
function getRSSContent(entry: StarlightBlogEntry): Promise<string> { | ||
return renderMarkdownToHTML(entry.body) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import rss from '@astrojs/rss' | ||
import type { APIRoute } from 'astro' | ||
|
||
import { getRSSOptions, getRSSStaticPaths } from '../libs/rss' | ||
|
||
export function getStaticPaths() { | ||
return getRSSStaticPaths() | ||
} | ||
|
||
export const GET: APIRoute = async ({ site }) => { | ||
return rss(await getRSSOptions(site)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import type { StarlightUserConfig } from '@astrojs/starlight/types' | ||
import { describe, expect, test } from 'vitest' | ||
|
||
import { getDefaultLocale } from '../../../libs/i18n' | ||
|
||
describe('getDefaultLocale', () => { | ||
test('returns the default locale for the built-in default locale', () => { | ||
expect(getTestDefaultLocale({})).toBe('en') | ||
}) | ||
|
||
test('returns the default locale with a root locale', () => { | ||
expect( | ||
getTestDefaultLocale({ | ||
locales: { | ||
root: { label: 'Français', lang: 'fr' }, | ||
}, | ||
}), | ||
).toBe('fr') | ||
}) | ||
|
||
test('returns the default locale with a root locale and a default locale', () => { | ||
expect( | ||
getTestDefaultLocale({ | ||
defaultLocale: 'root', | ||
locales: { | ||
root: { label: 'Français', lang: 'fr' }, | ||
'zh-cn': { label: '简体中文', lang: 'zh-CN' }, | ||
}, | ||
}), | ||
).toBe('fr') | ||
}) | ||
|
||
test('returns the default locale with no root locale', () => { | ||
expect( | ||
getTestDefaultLocale({ | ||
defaultLocale: 'fr', | ||
locales: { | ||
fr: { label: 'Français', lang: 'fr' }, | ||
'zh-cn': { label: '简体中文', lang: 'zh-CN' }, | ||
}, | ||
}), | ||
).toBe('fr') | ||
}) | ||
|
||
test('returns the default locale with non root single locale', () => { | ||
expect( | ||
getTestDefaultLocale({ | ||
defaultLocale: 'fr', | ||
locales: { | ||
fr: { label: 'Français', lang: 'fr' }, | ||
}, | ||
}), | ||
).toBe('fr') | ||
}) | ||
}) | ||
|
||
function getTestDefaultLocale(config: Partial<StarlightUserConfig>) { | ||
return getDefaultLocale(config as StarlightUserConfig) | ||
} |
Oops, something went wrong.