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:
commit
127bcd22c9
|
@ -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.
|
|
@ -2,11 +2,15 @@ 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',
|
||||
|
@ -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'
|
||||
|
|
|
@ -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
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
|
@ -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>
|
|
@ -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>
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue