Starlight-GhostCMS: Add 2 new pages, and social icons (#73)

Just a quick patch to add the following

- About page that will turn on if a GhostCMS page with the slug "about"
is available (This is true in any default Ghost install)
- Add Authors page
- Adds Twitter & Facebook social icons from ghost to Starlight if not
filled by user in Starlight config
This commit is contained in:
Adam Matthiesen 2024-02-21 16:43:58 -08:00 committed by GitHub
commit 127bcd22c9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 285 additions and 8 deletions

View File

@ -0,0 +1,5 @@
---
"@matthiesenxyz/starlight-ghostcms": patch
---
Adds 2 new pages, Authors, and about page(Link will disappear if you dont have the default ghost about page with slug "about"). Also adds auto links from ghost settings for twitter and facebook if not set my the user in starlight.

View File

@ -2,12 +2,16 @@ import type { StarlightPlugin, StarlightUserConfig } from '@astrojs/starlight/ty
import type { AstroIntegrationLogger } from 'astro'
import { type StarlightGhostConfig, validateConfig } from './src/schemas/config'
import { vitePluginStarlightGhostConfig } from './src/integrations/vite'
import { facebook, getSettings, invariant, twitter } from './src/utils/api'
const settings = await getSettings()
export type { StarlightGhostConfig }
export default function starlightGhostCMS(userConfig?: StarlightGhostConfig): StarlightPlugin {
const config: StarlightGhostConfig = validateConfig(userConfig)
invariant(settings, "Settings not available... check your api key/url")
return {
name: '@matthiesenxyz/starlight-ghostcms-plugin',
hooks: {
@ -15,7 +19,9 @@ export default function starlightGhostCMS(userConfig?: StarlightGhostConfig): St
updateStarlightConfig({
social: {
...starlightConfig.social,
rss: `${astroConfig.site}/rss.xml`
rss: `${astroConfig.site}/rss.xml`,
twitter: twitter(settings.twitter?settings.twitter:""),
facebook: facebook(settings.facebook?settings.facebook:""),
},
components: {
...starlightConfig.components,
@ -39,6 +45,15 @@ export default function starlightGhostCMS(userConfig?: StarlightGhostConfig): St
entrypoint: '@matthiesenxyz/starlight-ghostcms/routes/[slug].astro',
prerender: true,
})
injectRoute({
pattern: '/blog/about',
entrypoint: '@matthiesenxyz/starlight-ghostcms/routes/about.astro',
prerender: true,
})
injectRoute({
pattern: '/blog/authors',
entrypoint: '@matthiesenxyz/starlight-ghostcms/routes/authors.astro',
})
injectRoute({
pattern: '/rss.xml',
entrypoint: '@matthiesenxyz/starlight-ghostcms/routes/rss.xml.ts'

View File

@ -46,6 +46,8 @@
"./overrides/Sidebar.astro": "./src/overrides/Sidebar.astro",
"./overrides/SiteTitle.astro": "./src/overrides/SiteTitle.astro",
"./routes/index.astro": "./src/routes/index.astro",
"./routes/about.astro": "./src/routes/about.astro",
"./routes/authors.astro": "./src/routes/authors.astro",
"./routes/[slug].astro": "./src/routes/[slug].astro",
"./routes/rss.xml.ts": "./src/routes/rss.xml.ts",
"./schema": "./src/schemas/config.ts"

File diff suppressed because one or more lines are too long

View File

@ -7,11 +7,11 @@ interface Props {
const { author } = Astro.props
const isLink = author.website !== undefined
const isLink = author.slug !== undefined
const Element = isLink ? 'a' : 'div'
---
<Element href={isLink ? author.website : undefined} class="author">
<Element href={isLink ? '/blog/authors' : undefined} class="author">
{author.profile_image && <img alt={author.name} src={author.profile_image} />}
<div class="text">
<div class="name">{author.name}</div>

View File

@ -3,23 +3,63 @@ import StarlightSidebar from '@astrojs/starlight/components/Sidebar.astro'
import type { Props } from '@astrojs/starlight/props'
import config from 'virtual:starlight-ghost-config'
import { isBlogPostPage, isBlogRoot } from '../utils/page'
import { getAllPosts } from '../utils/api'
import { getAllPages, getAllPosts, getSluggedPage } from '../utils/api/api-functions.js'
import type { SidebarEntry } from './sidebartypes'
export async function getRecentBlogEntries(){
const entries = await getAllPosts()
return entries.slice(0, config.recentPostCount)
}
export async function getBlogPageEntries(){
const entries = await getAllPages()
return entries;
}
export function checkpath(path: string){
if ( path.slice(0, 5) === "/blog" ){
return true
} else { return false }
}
export function isAbout(path: string){
if ( path === "/blog/about" ){
return true
} else { return false }
}
export function isAuthors(path: string){
if ( path === "/blog/authors" ){
return true
} else { return false }
}
const isBlog = checkpath(Astro.url.pathname)
const recentEntries = isBlog ? await getRecentBlogEntries() : []
const aboutPage = await getSluggedPage("about");
const AboutEntry:SidebarEntry = {
attrs: {}, badge: undefined,
href: '/blog/about',
isCurrent: isAbout(Astro.url.pathname),
type: 'link',
label: aboutPage?.post?.title
}
const emptyEntry:SidebarEntry = { attrs: {}, badge: undefined,
href: '#', isCurrent: false, type: 'link', label: '', }
const about = aboutPage?AboutEntry:emptyEntry
const blogSidebar: Props['sidebar'] = isBlog
? [
about,
{
attrs: {},
badge: undefined,
href: '/blog/authors',
isCurrent: isAuthors(Astro.url.pathname),
label: 'Our Authors',
type: 'link',
},
{
attrs: {},
badge: undefined,
@ -33,7 +73,7 @@ const blogSidebar: Props['sidebar'] = isBlog
collapsed: false,
entries: recentEntries.map((blogEntry) => ({
attrs: {},
badge: undefined,
badge: blogEntry.featured?({text: "⭐", variant: "note"}):undefined,
href: `/blog/${blogEntry.slug}`,
isCurrent: isBlogPostPage(Astro.props.slug, `blog/${blogEntry.slug}`),
label: blogEntry.title,

View File

@ -1,12 +1,11 @@
---
import type { Props } from "@astrojs/starlight/props";
import AstrolightSiteTitle from "@astrojs/starlight/components/SiteTitle.astro";
import config from 'virtual:starlight-ghost-config'
---
<AstrolightSiteTitle {...Astro.props} />
<div>
<a href="/blog">{config.title}</a>
<a href="/blog">Blog</a>
</div>
<style>

View File

@ -0,0 +1,46 @@
import { z } from 'astro/zod';
import type { AstroBuiltinAttributes } from 'astro';
import type { HTMLAttributes } from 'astro/types';
const linkHTMLAttributesSchema = z.record(
z.union([z.string(), z.number(), z.boolean(), z.undefined()])
) as z.Schema<Omit<HTMLAttributes<'a'>, keyof AstroBuiltinAttributes | 'children'>>;
export type LinkHTMLAttributes = z.infer<typeof linkHTMLAttributesSchema>;
const badgeSchema = () =>
z.object({
variant: z.enum(['note', 'danger', 'success', 'caution', 'tip', 'default']).default('default'),
text: z.string(),
});
export const BadgeConfigSchema = () =>
z
.union([z.string(), badgeSchema()])
.transform((badge) => {
if (typeof badge === 'string') {
return { variant: 'default' as const, text: badge };
}
return badge;
})
.optional();
export type Badge = z.output<ReturnType<typeof badgeSchema>>;
export interface Link {
type: 'link';
label: string;
href: string;
isCurrent: boolean;
badge: Badge | undefined;
attrs: LinkHTMLAttributes;
}
interface Group {
type: 'group';
label: string;
entries: (Link | Group)[];
collapsed: boolean;
badge: Badge | undefined;
}
export type SidebarEntry = Link | Group;

View File

@ -0,0 +1,36 @@
---
import config from 'virtual:starlight-ghost-config'
import Metadata from '../components/Metadata.astro'
import Page from '../components/Page.astro'
//import PrevNextLinks from '../components/PrevNextLinks.astro'
import { getPageProps } from '../utils/page'
import { getSluggedPage } from '../utils/api'
const aboutPage = await getSluggedPage("about");
//const { entries, nextLink, prevLink } = Astro.props
const pageProps = getPageProps(aboutPage?.post?.title)
---
<Page {...pageProps}>
{config.supportGhost && (
<div id="pghost">Powered by <a href="https://ghost.org">Ghost</a></div>
)}
<Metadata entry={aboutPage.post} />
<Fragment set:html={aboutPage.post.html} />
<footer class="not-content">
<!--PrevNextLinks next={nextLink} prev={prevLink} /-->
</footer>
</Page>
<style>
#pghost {
color: gray;
position: absolute;
top: 4rem;
}
#pghost a {
color: gray;
}
</style>

View File

@ -0,0 +1,48 @@
---
import config from 'virtual:starlight-ghost-config'
import Page from '../components/Page.astro'
//import PrevNextLinks from '../components/PrevNextLinks.astro'
import { getAllAuthors } from '../utils/api/api-functions'
import { getPageProps } from '../utils/page'
import AdvancedAuthorCard from '../components/AdvancedAuthorCard.astro';
//const { entries, nextLink, prevLink } = Astro.props
const { authors } = await getAllAuthors();
const pageProps = getPageProps("Our Authors")
---
<Page {...pageProps}>
{config.supportGhost && (
<div id="pghost">Powered by <a href="https://ghost.org">Ghost</a></div>
)}
<div class="authors">
<ul>
{authors.map((author: any) => (
<li>
<AdvancedAuthorCard {author} />
</li>
))}
</ul>
<footer class="not-content">
<!--PrevNextLinks next={nextLink} prev={prevLink} /-->
</footer>
</Page>
<style>
#pghost {
color: gray;
position: absolute;
top: 4rem;
}
#pghost a {
color: gray;
}
ul {
list-style: none;
}
</style>

View File

@ -106,6 +106,22 @@ export const getAllPages = async () => {
return pages;
};
export const getSluggedPage = async (slug:string) => {
const results = await api.pages
.read({slug: slug})
.include({
authors: true,
tags: true,
}).fetch()
if (!results.success) {
throw new Error(results.errors.map((e) => e.message).join(", "));
}
return {
post: results.data,
};
};
export const getSettings = async () => {
const res = await api.settings.fetch();
if (res.success) {