@dbosoft/nextjs-site-core
v3.0.3
Published
Server-first site framework for dbosoft Next.js sites
Keywords
Readme
@dbosoft/nextjs-site-core
Server-first site framework for dbosoft Next.js sites. Provides navigation, footer, SEO, analytics, theming, and shared UI components used across all dbosoft websites.
Installation
This is a workspace package — add "@dbosoft/nextjs-site-core": "workspace:*" to your package.json.
Required Dependencies
{
"dependencies": {
"@dbosoft/nextjs-site-core": "workspace:*",
"@dbosoft/nextjs-site-marketing": "workspace:*",
"@dbosoft/nextjs-plugin": "workspace:*",
"@dbosoft/tailwind-config": "workspace:*",
"@dbosoft/react-uicore": "workspace:*",
"@dbosoft/nextjs-consent-manager": "workspace:*",
"@dbosoft/web-types": "workspace:*",
"@headlessui/react": "^2.2.1",
"@heroicons/react": "^2.2.0",
"clsx": "^2.1.0",
"framer-motion": "^11.0.0",
"next": "^16.0.0",
"next-themes": "^0.4.4",
"next-intl": "^4.8.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"sass": "^1.80.0",
"fathom-client": "^3.7.0",
"@vercel/speed-insights": "^1.1.0"
},
"devDependencies": {
"tailwindcss": "^4.0.0",
"@tailwindcss/forms": "^0.5.9",
"@tailwindcss/typography": "^0.5.15"
}
}Subpath Exports
| Import | Description |
|--------|-------------|
| ./types | TypeScript interfaces: LinkItem, SiteCoreStaticConfig, CTALink, AuthConfig, FooterColumn, etc. |
| ./server | Server components: HtmlShell, AppShell, HeadNav, HeadNavSSR, Footer |
| ./client | Client components: HeadNavClient, NavigationProvider, PrimaryNav, SecondaryNav, MobileNavigation, Breadcrumb, Tracking |
| ./navigation | Pure functions: generateNavigationStructure(), getBreadcrumbs(), generateFooterNavigation(), getQuickLinks() |
| ./ui | Client UI: ThemeSelector, Avatar, FormInput, ResponsiveTable, AppLink, TabsClient |
| ./ui/server | Server-only UI: Tabs, TabsContent |
| ./seo | SEO: StructuredData, ProductPageSEO, FAQSchema, HowToSchema, PageAISchema, AIContent, generateSitemapEntries() |
| ./analytics | Analytics: ConsentManagerLazy, Tracking |
| ./page-navigation | Page-level navigation context |
| ./hooks | React hooks: useIsVisible, useTypewriter, useScrollProgress |
| ./i18n | i18n utilities: createRequestConfig(), localizeConfig(), LanguageSwitcher |
| ./i18n/default-request | Default next-intl config (English-only, framework messages). Use when not opting into i18n. |
| ./tailwind | Tailwind config preset |
| ./css | Framework CSS (framework.css) |
Setup
1. Next.js Configuration
The site requires two Next.js plugins:
@dbosoft/nextjs-plugin— SVG component support, auto-discovers and transpiles@dbosoftpackagesnext-intl/plugin— Required by the framework for translations (even without multi-locale support)
// next.config.mjs
import createNextIntlPlugin from 'next-intl/plugin'
import withDbosoftPlugin from '@dbosoft/nextjs-plugin'
const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts')
/** @type {import('next').NextConfig} */
const nextConfig = {}
export default withNextIntl(
withDbosoftPlugin({})(nextConfig)
)2. i18n Request Config
For apps that don't need multi-locale support, create a one-line re-export of the default config:
// src/i18n/request.ts
export { default } from '@dbosoft/nextjs-site-core/i18n/default-request'This loads the framework's built-in English translations (footer, nav, theme selector, etc.) without any app-level setup.
For apps that opt into full i18n, see Multi-locale i18n below.
3. TypeScript Configuration
Add @dbosoft/web-types to your tsconfig for global type declarations (SVG modules, etc.):
{
"compilerOptions": {
"types": ["@dbosoft/web-types"]
}
}4. Tailwind 4 Configuration
// tailwind.config.ts
import type { Config } from 'tailwindcss'
import nextjsConfig from '@dbosoft/tailwind-config/nextjs'
import { resolveDbosoftContent } from '@dbosoft/tailwind-config/resolve-content'
const config: Config = {
presets: [nextjsConfig],
content: [
'./src/**/*.{js,ts,jsx,tsx,mdx}',
...resolveDbosoftContent(),
],
darkMode: 'selector',
}
export default config5. Framework CSS (Tailwind 4)
/* src/app/css/style.css */
@import "tailwindcss";
@config "../../../tailwind.config.ts";
/* Framework: design tokens + framework utilities */
@import '@dbosoft/nextjs-site-core/css';The @config path is relative from the CSS file to the tailwind config at the project root.
6. Root Layout
// src/app/layout.tsx
import './css/style.css'
import { HtmlShell, AppShell } from '@dbosoft/nextjs-site-core/server'
import { siteConfig } from '@/lib/site-core-config'
export default function AppLayout({ children }: { children: React.ReactNode }) {
return (
<HtmlShell>
<AppShell config={siteConfig}>
{children}
</AppShell>
</HtmlShell>
)
}7. Default Layout with Navigation
// src/app/(default)/layout.tsx
import { HeadNav } from '@dbosoft/nextjs-site-core/server'
import { siteConfig } from '@/lib/site-core-config'
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<HeadNav
config={siteConfig}
logoSlot={<span className="text-lg font-semibold">My Product</span>}
/>
{children}
</>
)
}8. Site Configuration
// src/lib/site-core-config.tsx
import { createSiteConfig, LinkType } from '@dbosoft/nextjs-site-core/types'
export const siteConfig = createSiteConfig({
siteUrl: 'https://your-site.io',
routes: { home: '/', docs: '/docs', pricing: '/pricing' },
externalLinks: { dbosoft: 'https://www.dbosoft.eu' },
footerColumns: [
{ id: 'get-started', label: 'Get Started', position: 'main', order: 1 },
],
navGroups: [
{
id: 'get-started',
name: 'Get Started',
sections: [{ id: 'quick-start', title: 'Quick Start' }],
},
],
links: {
home: { linkType: LinkType.Core, href: '/', title: 'Home', hideInFooter: true, hideInMainNav: true },
pricing: { linkType: LinkType.Core, href: '/pricing', title: 'Pricing', footerCategory: 'get-started', navSection: 'quick-start' },
},
copyrightText: '(c) 2026 dbosoft GmbH',
ctaLink: { key: 'pricing', label: 'Get Started' },
headerLinks: [{ key: 'docs', label: 'Docs', href: '/docs' }],
})Optional Features (Opt-in)
Authentication
Auth is fully pluggable — the framework has no auth library dependency. To add auth:
- Wrap your layout with your own
SessionProvider(from your auth library) - Pass an
authSlotcomponent toHeadNavthat renders sign-in/sign-out UI
// Your auth UI component (client component)
function AuthUI({ variant }: { variant: 'desktop' | 'mobile' }) {
// Use your auth library's hooks here (next-auth, custom, etc.)
return variant === 'desktop' ? <DesktopAuth /> : <MobileAuth />
}
// In your layout
<HeadNav config={siteConfig} logoSlot={<Logo />} authSlot={AuthUI} />The authSlot component receives a variant prop ('desktop' | 'mobile') and is rendered in the appropriate position in the header and mobile drawer.
Multi-locale i18n
Full i18n requires the following setup:
1. Define routing
// src/i18n/routing.ts
import { defineRouting } from 'next-intl/routing'
export const routing = defineRouting({
locales: ['en-us', 'de-de'],
defaultLocale: 'en-us',
localePrefix: 'always',
})2. Create request config with message loading
// src/i18n/request.ts
import { createRequestConfig } from '@dbosoft/nextjs-site-core/i18n'
import { routing } from './routing'
// App-specific messages
async function loadMessages(locale: string) {
try {
return (await import(`../../messages/${locale}.json`)).default
} catch {
return (await import('../../messages/en-us.json')).default
}
}
export default createRequestConfig({
routing,
loadMessages,
packages: [
// Add message loaders from packages that ship translations:
// loadDocsMessages, loadArticlesMessages, etc.
],
})Messages are deep-merged in this order: framework messages > auto-discovered addon messages > package messages > app messages. The framework auto-discovers @dbosoft/* packages with a messages/ directory.
3. Create the locale proxy (Next.js 16)
Next.js 16 uses a proxy pattern instead of middleware.ts:
// src/proxy.ts
import createIntlMiddleware from 'next-intl/middleware'
import { type NextRequest } from 'next/server'
import { routing } from './i18n/routing'
const intlMiddleware = createIntlMiddleware(routing)
export function proxy(request: NextRequest) {
return intlMiddleware(request)
}
export const config = {
matcher: ['/', '/(de-de|en-us)/:path*'],
}The matcher should list your locale prefixes explicitly.
4. Add [locale] route segment
// src/app/[locale]/layout.tsx
import type { ReactNode } from 'react'
import { HtmlShell, AppShell } from '@dbosoft/nextjs-site-core/server'
import { getMessages } from 'next-intl/server'
import { siteConfig } from '@/lib/site-core-config'
import { routing } from '@/i18n/routing'
export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale }))
}
export default async function LocaleLayout({
children,
params,
}: {
children: ReactNode
params: Promise<{ locale: string }>
}) {
const { locale } = await params
const messages = await getMessages()
return (
<HtmlShell locale={locale}>
<AppShell config={siteConfig} messages={messages}>
{children}
</AppShell>
</HtmlShell>
)
}Key points:
- Call
getMessages()server-side in the locale layout - Pass
messagestoAppShell— it wraps children withNextIntlClientProvider - Pass
localetoHtmlShellfor the<html lang>attribute - Use
generateStaticParams()to pre-render all locale variants
5. Add i18n to site config
export const siteConfig: SiteCoreStaticConfig = {
// ... other config
i18n: {
locales: ['en-us', 'de-de'],
defaultLocale: 'en-us',
localePrefix: 'always',
},
}This enables the locale selector in the navigation UI.
6. Per-locale message files
messages/
en-us.json
de-de.jsonArchitecture
Design Principles
- Server-first: Layout components have server + client pairs. Server components render static HTML (zero JS). Client components add interactivity only where needed.
- Static rendering by default: The framework never calls
auth()in layouts. Pages stay statically renderable. Auth UI is handled client-side viauseSession(). - Config via props: Server components receive typed config as props. Client components receive serializable config as props. No global singletons.
- Component slots for non-serializable content: Logos, icons, search, promos are passed as
ReactNodeslots — server-rendered at the app level, passed to framework components.
Config Type System
// Serializable — crosses server->client boundary as props
interface SiteCoreStaticConfig {
siteUrl: string
routes: Record<string, string>
externalLinks: Record<string, string>
linkRegistry: Record<string, LinkItem>
navigationGroups: NavigationGroup[]
footerColumns?: FooterColumn[]
copyrightText?: string
docsPathPrefix?: string
ctaLink?: CTALink
headerLinks?: HeaderLink[]
i18n?: I18nConfig // Optional — enables multi-locale support
seo?: SiteSEOConfig // Optional — SEO defaults
auth?: AuthConfig // Optional — enables SessionProvider + auth UI
}
interface AuthConfig {
providerId: string
profileUrl: string
}Navigation Layers
+---------------------------------------------------------------+
| PRIMARY NAV (fixed, always-dark bg-black) |
| [Logo] [MegaMenu Groups...] [CTA Button] [Links] [Auth]|
+---------------------------------------------------------------+
| SECONDARY NAV (sticky, themed) |
| [SubLogo / Breadcrumb] [Search?] [Quick Links ->] |
+---------------------------------------------------------------+Server/Client Composition
HeadNav (server, no 'use client')
+-- Suspense fallback: HeadNavSSR (server, static HTML)
+-- Suspended: HeadNavClient ('use client', interactive)
+-- NavigationProvider (scroll state)
+-- PrimaryNav (mega menu, auth via config.auth)
+-- SecondaryNav (scroll-aware breadcrumb)
+-- Breadcrumb (path-based)
+-- MobileNavigation (dialog)
+-- ScrollbarCompensationTheme Tokens
Semantic CSS class tokens that adapt to light/dark mode:
| Category | Classes |
|----------|---------|
| Backgrounds | bg-surface-base, bg-surface-raised, bg-section-alt, bg-card |
| Text | text-content-primary, text-content-secondary, text-content-muted |
| Borders | border-border |
| Brand | text-primary-normal, text-primary-light, bg-primary-normal |
