Skip to content
Open
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ public/docs-bundle-experimental.json

# testing folder for code samples and experiments
testing/

# scratch folder for temporary files and planning
scratch/
173 changes: 81 additions & 92 deletions astro.config.mjs
Original file line number Diff line number Diff line change
@@ -1,182 +1,171 @@
// @ts-check
import { defineConfig } from "astro/config";
import starlight from "@astrojs/starlight";
import starlightLinksValidatorPlugin from "starlight-links-validator";
import starlightLlmsTxt from "starlight-llms-txt";
import sitemap from "@astrojs/sitemap";
import { sidebar } from "./src/sidebar";
import { GOOGLE_DARK_THEME, GOOGLE_LIGHT_THEME } from "./src/google-theme";
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import starlightLinksValidatorPlugin from 'starlight-links-validator';
import starlightLlmsTxt from 'starlight-llms-txt';
import sitemap from '@astrojs/sitemap';
import { sidebar } from './src/sidebar';
import { GOOGLE_DARK_THEME, GOOGLE_LIGHT_THEME } from './src/google-theme';

const site = "https://genkit.dev";
const ogUrl = new URL("ogimage.png?v=1", site).href;
const site = 'https://genkit.dev';
const ogUrl = new URL('ogimage.png?v=1', site).href;

// https://astro.build/config
export default defineConfig({
// TODO: Update to genkit.dev before launch
site,
markdown: {
shikiConfig: {
langAlias: { dotprompt: "handlebars" },
langAlias: { dotprompt: 'handlebars' },
},
},
integrations: [
starlight({
favicon: "favicon.ico",
favicon: 'favicon.ico',
expressiveCode: {
themes: [GOOGLE_DARK_THEME, GOOGLE_LIGHT_THEME],
},
pagination: false,
title: "Genkit",
title: 'Genkit',
components: {
Sidebar: "./src/components/sidebar.astro",
Header: "./src/content/custom/header.astro",
Hero: "./src/content/custom/hero.astro",
Sidebar: './src/components/sidebar.astro',
Header: './src/content/custom/header.astro',
Hero: './src/content/custom/hero.astro',
Head: './src/content/custom/head.astro',
},
head: [
{
tag: "meta",
tag: 'meta',
attrs: {
property: "og:image",
property: 'og:image',
content: ogUrl,
width: "1085",
height: "377",
width: '1085',
height: '377',
},
},
{
tag: "link",
tag: 'link',
attrs: {
href: "https://fonts.gstatic.com",
rel: "preconnect",
href: 'https://fonts.gstatic.com',
rel: 'preconnect',
crossorigin: true,
},
},
{
tag: "link",
tag: 'link',
attrs: {
href: "https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500&display=swap",
rel: "stylesheet",
href: 'https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500&display=swap',
rel: 'stylesheet',
},
},
{
tag: "link",
tag: 'link',
attrs: {
href: "https://fonts.googleapis.com/css2?family=Google+Sans+Text:wght@400;500&display=swap",
rel: "stylesheet",
href: 'https://fonts.googleapis.com/css2?family=Google+Sans+Text:wght@400;500&display=swap',
rel: 'stylesheet',
},
},
{
tag: "link",
tag: 'link',
attrs: {
href: "https://fonts.googleapis.com/css2?family=Google+Sans+Mono:wght@400;500&display=swap",
rel: "stylesheet",
href: 'https://fonts.googleapis.com/css2?family=Google+Sans+Mono:wght@400;500&display=swap',
rel: 'stylesheet',
},
},
{
tag: "link",
tag: 'link',
attrs: {
href: "https://fonts.googleapis.com/css2?family=Google+Symbols&display=block",
rel: "stylesheet",
href: 'https://fonts.googleapis.com/css2?family=Google+Symbols&display=block',
rel: 'stylesheet',
},
},
],
plugins: [
starlightLinksValidatorPlugin(),
starlightLlmsTxt({
projectName: "Genkit",
description: "Open-source GenAI toolkit for JS, Go, and Python.",
projectName: 'Genkit',
description: 'Open-source GenAI toolkit for JS, Go, and Python.',
minify: { whitespace: false },
customSets: [
{
label: "Building AI Workflows",
description:
"Guidance on how to generate content and interact with LLM and image models using Genkit.",
label: 'Building AI Workflows',
description: 'Guidance on how to generate content and interact with LLM and image models using Genkit.',
paths: [
"docs/models",
"docs/context",
"docs/flows",
"docs/dotprompt",
"docs/chat",
"docs/tool-calling",
"docs/interrupts",
"docs/rag",
"docs/multi-agent",
"docs/evaluation",
"docs/local-observability",
"docs/errors/types",
'docs/models',
'docs/context',
'docs/flows',
'docs/dotprompt',
'docs/chat',
'docs/tool-calling',
'docs/interrupts',
'docs/rag',
'docs/multi-agent',
'docs/evaluation',
'docs/local-observability',
'docs/errors/types',
],
},
{
label: "Deploying AI Workflows",
label: 'Deploying AI Workflows',
description:
"Guidance on how to deploy Genkit code to various environments including Firebase and Cloud Run or use within a Next.js app.",
paths: [
"docs/firebase",
"docs/cloud-run",
"docs/deploy-node",
"docs/auth",
"docs/nextjs",
],
'Guidance on how to deploy Genkit code to various environments including Firebase and Cloud Run or use within a Next.js app.',
paths: ['docs/firebase', 'docs/cloud-run', 'docs/deploy-node', 'docs/auth', 'docs/nextjs'],
},
{
label: "Observing AI Workflows",
description:
"Guidance about Genkit's various observability features and how to use them.",
label: 'Observing AI Workflows',
description: "Guidance about Genkit's various observability features and how to use them.",
paths: [
"docs/observability/getting-started",
"docs/observability/authentication",
"docs/observability/advanced-configuration",
"docs/observability/telemetry-collection",
"docs/observability/troubleshooting",
'docs/observability/getting-started',
'docs/observability/authentication',
'docs/observability/advanced-configuration',
'docs/observability/telemetry-collection',
'docs/observability/troubleshooting',
],
},
{
label: "Writing Plugins",
description: "Guidance about how to author plugins for Genkit.",
paths: [
"docs/plugin-authoring",
"docs/plugin-authoring-evaluator",
],
label: 'Writing Plugins',
description: 'Guidance about how to author plugins for Genkit.',
paths: ['docs/plugin-authoring', 'docs/plugin-authoring-evaluator'],
},
{
label: "Plugin Documentation",
label: 'Plugin Documentation',
description:
"Provider-specific documentation for the Google AI, Vertex AI, Firebase, Ollama, Chroma, and Pinecone plugins.",
'Provider-specific documentation for the Google AI, Vertex AI, Firebase, Ollama, Chroma, and Pinecone plugins.',
paths: [
"docs/plugins/google-genai",
"docs/plugins/vertex-ai",
"docs/plugins/firebase",
"docs/plugins/ollama",
"docs/plugins/chroma",
"docs/plugins/pinecone",
'docs/plugins/google-genai',
'docs/plugins/vertex-ai',
'docs/plugins/firebase',
'docs/plugins/ollama',
'docs/plugins/chroma',
'docs/plugins/pinecone',
],
},
],
}),
],
logo: {
dark: "./src/assets/lockup_white_tight2.png",
light: "./src/assets/lockup_dark_tight.png",
dark: './src/assets/lockup_white_tight2.png',
light: './src/assets/lockup_dark_tight.png',
replacesTitle: true,
},
social: [
{
icon: "github",
label: "GitHub",
href: "https://github.com/firebase/genkit",
icon: 'github',
label: 'GitHub',
href: 'https://github.com/firebase/genkit',
},
{
icon: "discord",
label: "Discord",
href: "https://discord.gg/qXt5zzQKpc",
icon: 'discord',
label: 'Discord',
href: 'https://discord.gg/qXt5zzQKpc',
},
],
sidebar,
customCss: ["./src/tailwind.css"],
customCss: ['./src/tailwind.css'],
}),
sitemap(),
],
redirects: {
"/discord": 'https://discord.gg/qXt5zzQKpc',
'/discord': 'https://discord.gg/qXt5zzQKpc',
},
});
57 changes: 57 additions & 0 deletions scripts/refactor-tabs.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import fs from 'fs/promises';
import path from 'path';

const directoryPath = 'src/content/docs/unified-docs';

async function processFile(filePath) {
try {
let content = await fs.readFile(filePath, 'utf-8');
let changed = false;

if (content.includes('<Tabs syncKey="language">')) {
changed = true;

content = content.replace(/<Tabs syncKey="language">/g, '<LangTabs>');
content = content.replace(/<\/Tabs>/g, '</LangTabs>');

content = content.replace(/<TabItem label="JavaScript"[^>]*>/g, '<LangTabItem lang="js">');
content = content.replace(/<TabItem label="Go"[^>]*>/g, '<LangTabItem lang="go">');
content = content.replace(/<TabItem label="Python"[^>]*>/g, '<LangTabItem lang="python">');
content = content.replace(/<\/TabItem>/g, '</LangTabItem>');

const importRegex = /import { Tabs, TabItem } from '@astrojs\/starlight\/components';/g;
const newImport =
"import LangTabs from '../../../components/LangTabs.astro';\nimport LangTabItem from '../../../components/LangTabItem.astro';";

if (importRegex.test(content)) {
content = content.replace(importRegex, newImport);
}
}

if (changed) {
await fs.writeFile(filePath, content, 'utf-8');
console.log(`Updated: ${filePath}`);
}
} catch (error) {
console.error(`Error processing file ${filePath}:`, error);
}
}

async function walk(dir) {
const files = await fs.readdir(dir, { withFileTypes: true });
for (const file of files) {
const res = path.resolve(dir, file.name);
if (file.isDirectory()) {
await walk(res);
} else {
if (res.endsWith('.mdx')) {
await processFile(res);
}
}
}
}

console.log('Starting tab replacement script...');
walk(directoryPath).then(() => {
console.log('Tab replacement script finished.');
});
11 changes: 11 additions & 0 deletions src/components/LangTabItem.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
// src/components/LangTabItem.astro
interface Props {
lang: 'js' | 'go' | 'python';
}

const { lang } = Astro.props;
---
<div class="lang-tab-item" data-lang={lang} role="tabpanel">
<slot />
</div>
38 changes: 38 additions & 0 deletions src/components/LangTabs.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
// src/components/LangTabs.astro
---
<div class="lang-tabs" role="tablist">
<slot />
</div>

<script>
function updateTabVisibility(lang: string) {
document.querySelectorAll('.lang-tab-item').forEach(item => {
const tab = item as HTMLElement;
if (tab.dataset.lang === lang) {
tab.style.display = 'block';
} else {
tab.style.display = 'none';
}
});
}

function initializeTabs() {
if (window.languagePreferenceEnhancer) {
const currentLang = window.languagePreferenceEnhancer.getCurrentLanguage();
updateTabVisibility(currentLang);
}
}

document.addEventListener('DOMContentLoaded', () => {
initializeTabs();
window.addEventListener('language-preference-changed', (e) => {
updateTabVisibility((e as CustomEvent).detail.language);
});
});

// In case the script runs after DOMContentLoaded
if (document.readyState !== 'loading') {
initializeTabs();
}
</script>
Loading