starlight-digital-garden
Version:
Digital garden for starlight
148 lines (139 loc) • 4.7 kB
text/typescript
import type {
StarlightPlugin,
StarlightUserConfig,
} from "@astrojs/starlight/types";
import type { AstroIntegrationLogger } from "astro";
import { defineIntegration } from "astro-integration-kit";
import { z } from "astro/zod";
import rehypeExternalLinks from "rehype-external-links";
import robotsTxt from "astro-robots-txt";
import remarkDataview from "@braindb/remark-dataview";
import { brainDbAstro, getBrainDb } from "@braindb/astro";
export { getBrainDb };
export const astroDigitalGarden = defineIntegration({
name: "astro-digital-garden",
optionsSchema: z
.object({
remarkDataview: z.boolean(),
rehypeExternalLinks: z.union([
z.literal("arrow"),
z.literal("icon"),
z.literal("off"),
]),
})
.partial()
.optional(),
setup({ options }) {
return {
hooks: {
"astro:config:setup": ({ config, updateConfig }) => {
const newConfig = {
markdown: {
remarkPlugins: [
...(options?.remarkDataview === true
? [[remarkDataview, { getBrainDb }]]
: []),
...config.markdown.remarkPlugins,
],
rehypePlugins: [
...(options?.rehypeExternalLinks === "off"
? []
: [
[
rehypeExternalLinks,
{
target: "_blank",
rel: ["nofollow", "noopener"],
...(options?.rehypeExternalLinks === "icon"
? {
content: { type: "text", value: "" },
contentProperties: (x: any) => {
const hostname = new URL(x.properties.href)
.hostname;
return {
class: "external-icon",
style: `--icon: url(https://external-content.duckduckgo.com/ip3/${hostname}.ico)`,
};
},
}
: {
content: { type: "text", value: " ↗" }, // ⤴
contentProperties: {
"aria-hidden": true,
class: "no-select",
},
}),
},
],
]),
...config.markdown.rehypePlugins,
],
},
};
updateConfig(newConfig);
},
},
};
},
});
type SDGOptions = {
robotsTxt?: boolean;
rehypeExternalLinks?: "arrow" | "icon";
remarkDataview?: boolean;
// TODO: BrainDbOptions
// TODO: maybe options to disable previews, backlinks, wikilinks etc?
};
export default function starlightDigitalGarden(
options?: SDGOptions
): StarlightPlugin {
return {
name: "starlight-digital-garden",
hooks: {
setup({
config: starlightConfig,
logger,
updateConfig: updateStarlightConfig,
addIntegration,
}) {
addIntegration(astroDigitalGarden(options));
addIntegration(brainDbAstro());
if (options?.robotsTxt !== false) addIntegration(robotsTxt());
updateStarlightConfig({
// pagination doesn't make sense in the context of digital garden
pagination: false,
components: {
...starlightConfig.components,
...overrideStarlightComponent(
starlightConfig.components,
logger,
"TableOfContents"
),
...overrideStarlightComponent(
starlightConfig.components,
logger,
"PageFrame"
),
},
});
},
},
};
}
function overrideStarlightComponent(
components: StarlightUserConfig["components"],
logger: AstroIntegrationLogger,
component: keyof NonNullable<StarlightUserConfig["components"]>
) {
if (components?.[component]) {
logger.warn(
`It looks like you already have a \`${component}\` component override in your Starlight configuration.`
);
logger.warn(
`To use \`starlight-digital-garden\`, either remove your override or update it to render the content from \`starlight-digital-garden/overrides/${component}.astro\`.`
);
return {};
}
return {
[component]: `starlight-digital-garden/overrides/${component}.astro`,
};
}