Files
nibiru-framework.com/docs/astro.config.mjs
stephan ab897b8a81 Wire Google Analytics 4 (G-V8QWB45G6X) alongside Umami
Adds gtag.js to the production head so Search Console can cross-reference
GA traffic. Same gating as Umami — production builds only, never injected
on dev. Three head entries:

  1. Umami (kept) — self-hosted, DNT-aware, GDPR-light
  2. Google's gtag loader (async)
  3. Inline init: window.dataLayer + gtag('config', 'G-V8QWB45G6X')

Both analytics run side-by-side; pick one or both in the GA dashboard.
A GDPR consent banner is not added — configure IP anonymisation +
consent mode v2 in the GA property settings if you intend to serve EU
visitors without explicit cookie acceptance.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 20:02:45 +02:00

413 lines
13 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// @ts-check
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import sitemap from '@astrojs/sitemap';
import node from '@astrojs/node';
import AstroPWA from '@vite-pwa/astro';
export default defineConfig({
site: 'https://nibiru-framework.com',
output: 'server',
adapter: node({ mode: 'standalone' }),
// Disable Astro's dev-mode floating toolbar — it's the small dark bar with
// component-inspect controls. Useful for Astro debugging, not needed for
// reviewing the design.
devToolbar: { enabled: false },
redirects: {
'/': '/en/',
// Bing/Yandex/IndexNow probe /sitemap.xml directly. Astro's sitemap
// integration emits sitemap-index.xml + sitemap-0.xml; add a 301 so
// either path resolves. Both are also referenced in robots.txt.
'/sitemap.xml': '/sitemap-index.xml',
},
integrations: [
AstroPWA({
registerType: 'autoUpdate',
includeAssets: [
'favicon.svg',
'img/nibiru-logo.png',
'img/lifecycle.svg',
],
manifest: {
name: 'Nibiru — Modular MMVC PHP Framework',
short_name: 'Nibiru',
description:
'A modular MMVC PHP framework for builders who ship. First-class AI, the Atelier × Cosmos design system, on-brand docs.',
start_url: '/en/',
scope: '/',
display: 'standalone',
orientation: 'portrait-primary',
background_color: '#fdf6df',
theme_color: '#7c7bb8',
lang: 'en',
categories: ['developer-tools', 'productivity', 'education'],
icons: [
{ src: '/img/pwa-192.png', sizes: '192x192', type: 'image/png' },
{ src: '/img/pwa-512.png', sizes: '512x512', type: 'image/png' },
{
src: '/img/pwa-512-maskable.png',
sizes: '512x512',
type: 'image/png',
purpose: 'maskable',
},
],
shortcuts: [
{
name: 'Quick Start',
short_name: 'Start',
url: '/en/start/quick-start/',
description: 'Build your first Nibiru page in five minutes.',
},
{
name: 'AI module',
short_name: 'AI',
url: '/en/ai/module/overview/',
description: 'First-class AI in your Nibiru app.',
},
{
name: 'Why Nibiru',
short_name: 'Why',
url: '/en/why-nibiru/',
description: 'Differentiators with code references.',
},
],
},
workbox: {
navigateFallback: '/en/',
// SSR /api/* endpoints — never cache, always go to network.
navigateFallbackDenylist: [/^\/api\//],
// Don't precache the heavy hero illustrations — they're served
// from network and runtime-cached after first view.
globPatterns: [
'**/*.{html,css,js,svg,woff2,json,xml}',
'img/pwa-*.png',
'img/apple-touch-icon.png',
'img/nibiru-*.png',
'img/lotus-divider.png',
'img/showcase-*.png',
'img/hero-backdrop.png',
],
maximumFileSizeToCacheInBytes: 4 * 1024 * 1024,
runtimeCaching: [
{
urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i,
handler: 'StaleWhileRevalidate',
options: { cacheName: 'google-fonts-stylesheets' },
},
{
urlPattern: /^https:\/\/fonts\.gstatic\.com\/.*/i,
handler: 'CacheFirst',
options: {
cacheName: 'google-fonts-webfonts',
expiration: { maxEntries: 16, maxAgeSeconds: 60 * 60 * 24 * 365 },
},
},
{
urlPattern: /\/img\/.*\.(png|svg|jpg|jpeg|webp)$/i,
handler: 'CacheFirst',
options: {
cacheName: 'nibiru-images',
expiration: { maxEntries: 60, maxAgeSeconds: 60 * 60 * 24 * 30 },
},
},
],
},
devOptions: {
enabled: false, // PWA runs only in production builds
navigateFallback: '/en/',
},
}),
sitemap({
i18n: {
defaultLocale: 'en',
locales: { en: 'en', de: 'de', ja: 'ja', es: 'es', fr: 'fr' },
},
filter: (page) => !page.includes('/api/'),
}),
starlight({
title: 'Nibiru',
description:
'A modular MMVC PHP framework for rapid prototyping. Born among the old gods, built for modern builders.',
// Analytics — production-only.
// 1. Umami (self-hosted) — cookie-free, honours Do-Not-Track,
// no PII captured, no GDPR banner required.
// 2. Google Analytics 4 (gtag.js) — added for Search Console
// cross-linking + audience reach. Subject to GDPR; configure
// consent / IP-anonymisation in the GA property settings.
head: import.meta.env.PROD
? [
{
tag: 'script',
attrs: {
defer: true,
src: 'https://analytics.neuronetz.ai/script.js',
'data-website-id': '5f2143d2-775b-4269-afcd-2639381add47',
'data-do-not-track': 'true',
'data-exclude-search': 'true',
},
},
{
tag: 'script',
attrs: {
async: true,
src: 'https://www.googletagmanager.com/gtag/js?id=G-V8QWB45G6X',
},
},
{
tag: 'script',
content:
"window.dataLayer = window.dataLayer || [];\n" +
"function gtag(){dataLayer.push(arguments);}\n" +
"gtag('js', new Date());\n" +
"gtag('config', 'G-V8QWB45G6X');",
},
]
: [],
logo: {
src: './public/img/nibiru-logo.png',
replacesTitle: true,
alt: 'Nibiru — Create, Invent, Impress',
},
favicon: '/favicon.svg',
editLink: { baseUrl: 'https://github.com/alllinux/Nibiru/edit/master/docs/' },
lastUpdated: true,
defaultLocale: 'en',
locales: {
en: { label: 'English', lang: 'en' },
de: { label: 'Deutsch', lang: 'de' },
ja: { label: '日本語', lang: 'ja' },
es: { label: 'Español', lang: 'es' },
fr: { label: 'Français', lang: 'fr' },
},
customCss: [
// 1. Brand tokens (--nibiru-*). Mirrored from /design-system/ by
// scripts/sync-design-system.mjs on every dev/build.
'./src/styles/design-system/tokens.css',
// 2. Docs-system tokens — verbatim from the design handoff. Defines
// --space, --space-2/3, --plum, --star-soft, --nebula-cyan/rose/green,
// --note-fg, --r-md, --fs-base, etc. Must come BEFORE components.css
// and nibiru.css since both consume these vars.
'./src/styles/docs-system/tokens.css',
// 3. Docs-system components — verbatim from the handoff. Provides the
// .topnav / .sidebar / .toc / .prose / .code-block / .callout-* /
// .doc-table / .tab-* / .api-* / .card / .search-modal / .fab styles.
'./src/styles/docs-system/components.css',
// 4. Fonts (Starlight needs --sl-font set before its own theme runs)
'./src/styles/fonts.css',
// 5. Site-specific styles + Starlight overrides (splash sections,
// legacy aliases, oracle launcher, atelier-button shims).
'./src/styles/nibiru.css',
// 6. Starlight × handoff bridge — translates Starlight's actual class
// names (.top-level, a[aria-current='page'], starlight-toc,
// .sl-markdown-content, .pagination-links, .starlight-aside-*)
// into the handoff's visual rules. Loaded LAST so it can win the
// cascade over both Starlight's defaults and earlier styles.
'./src/styles/starlight-docs-bridge.css',
],
components: {
Hero: './src/components/GalaxyHero.astro',
Header: './src/components/BrandHeader.astro',
// Article header — emits .breadcrumbs / <h1><em> / .doc-lede / .doc-meta
PageTitle: './src/components/PageTitle.astro',
// Article footer — Pagination + .help-strip ("Was this page helpful?")
Footer: './src/components/Footer.astro',
// Lock to dark — Cosmos is dark-only by design.
ThemeSelect: './src/components/ThemeSelectStub.astro',
},
expressiveCode: {
themes: ['github-light', 'github-dark'],
shiki: {
langAlias: {
smarty: 'html',
tpl: 'html',
},
},
styleOverrides: {
borderRadius: '0.75rem',
frames: {
shadowColor: 'rgba(124, 123, 184, 0.28)',
},
},
},
social: [
{
icon: 'github',
label: 'GitHub',
href: 'https://github.com/alllinux/Nibiru',
},
],
sidebar: [
{
label: 'Get started',
translations: {
de: 'Erste Schritte',
ja: 'はじめに',
es: 'Primeros pasos',
fr: 'Premiers pas',
},
items: [
{
label: 'What is Nibiru?',
slug: 'start/what-is-nibiru',
translations: {
de: 'Was ist Nibiru?',
ja: 'Nibiru とは?',
es: '¿Qué es Nibiru?',
fr: 'Qu\'est-ce que Nibiru ?',
},
},
{
label: 'Why Nibiru, not Laravel',
slug: 'why-nibiru',
translations: {
de: 'Warum Nibiru, nicht Laravel',
ja: 'なぜ Nibiru なのか',
es: '¿Por qué Nibiru y no Laravel?',
fr: 'Pourquoi Nibiru, pas Laravel',
},
},
{
label: 'Installation',
slug: 'start/installation',
translations: {
de: 'Installation',
ja: 'インストール',
es: 'Instalación',
fr: 'Installation',
},
},
{
label: 'Quick Start',
slug: 'start/quick-start',
translations: {
de: 'Schnellstart',
ja: 'クイックスタート',
es: 'Inicio rápido',
fr: 'Démarrage rapide',
},
},
{
label: 'Project Structure',
slug: 'start/structure',
translations: {
de: 'Projektstruktur',
ja: 'プロジェクト構成',
es: 'Estructura del proyecto',
fr: 'Structure du projet',
},
},
{
label: 'Run It Locally',
slug: 'start/local-testing',
translations: {
de: 'Lokal ausführen',
ja: 'ローカル実行',
es: 'Ejecución local',
fr: 'Lancer en local',
},
},
{
label: 'Deployment',
slug: 'start/deployment',
translations: {
de: 'Deployment',
ja: 'デプロイメント',
es: 'Despliegue',
fr: 'Déploiement',
},
},
],
},
{
label: 'The framework',
translations: {
de: 'Das Framework',
ja: 'フレームワーク',
es: 'El framework',
fr: 'Le framework',
},
items: [
{ label: 'Architecture (MMVC)', slug: 'core/architecture' },
{ label: 'Bootstrap & Dispatcher', slug: 'core/dispatcher' },
{ label: 'Routing', slug: 'core/routing' },
{ label: 'Controllers', slug: 'core/controllers' },
{ label: 'Views & Smarty', slug: 'core/views' },
{ label: 'Models', slug: 'core/models' },
{ label: 'Modules', slug: 'core/modules' },
{ label: 'Forms', slug: 'core/forms' },
{ label: 'Database & Migrations', slug: 'core/database' },
{ label: 'Auth', slug: 'core/auth' },
{ label: 'Config & Settings', slug: 'core/config' },
{ label: 'Pagination', slug: 'core/pagination' },
{ label: 'Registry', slug: 'core/registry' },
],
},
{
label: 'CLI',
translations: {
de: 'CLI',
ja: 'CLI',
es: 'CLI',
fr: 'CLI',
},
items: [
{ label: 'Overview', slug: 'cli/overview' },
{ label: 'Modules & Controllers', slug: 'cli/scaffolding' },
{ label: 'Migrations', slug: 'cli/migrations' },
{ label: 'CMS Pages', slug: 'cli/cms' },
],
},
{
label: 'Design System',
translations: {
de: 'Design-System',
ja: 'デザインシステム',
es: 'Sistema de diseño',
fr: 'Système de design',
},
items: [
{ label: 'Overview', slug: 'design/overview' },
{ label: 'Palette', slug: 'design/palette' },
{ label: 'Typography', slug: 'design/typography' },
{ label: 'Components', slug: 'design/components' },
{ label: 'Motion', slug: 'design/motion' },
],
},
{
label: 'In production',
translations: {
de: 'Im Einsatz',
ja: '実例',
es: 'En producción',
fr: 'En production',
},
items: [
{ label: 'Real-World Projects', slug: 'showcase/projects' },
{ label: 'Patterns from Production', slug: 'showcase/patterns' },
],
},
{
label: 'AI in Nibiru',
translations: {
de: 'KI in Nibiru',
ja: 'Nibiru の AI',
es: 'IA en Nibiru',
fr: "L'IA dans Nibiru",
},
items: [
{ label: 'The AI module', slug: 'ai/module/overview' },
{ label: 'Chat plugin', slug: 'ai/module/chat' },
{ label: 'Embed plugin', slug: 'ai/module/embed' },
{ label: 'RAG plugin', slug: 'ai/module/rag' },
{ label: 'Agent plugin', slug: 'ai/module/agent' },
{ label: 'Training nibiru-coder', slug: 'ai/module/training' },
{ label: 'Ask the Oracle', slug: 'ai/oracle' },
{ label: 'Training corpus (LoRA)', slug: 'ai/corpus' },
{ label: 'Roadmap', slug: 'ai/roadmap' },
],
},
],
}),
],
});