Add Drupal headless stack with Next.js frontend

- Add Next.js frontend service (nextjs) with Dockerfile and source
- Update docker-compose.yml: image names, Drupal 11.3.3, nextjs service
- Add docker-compose.override.yml.disabled for dev hot-reload
- Add install-headless-modules.sh for OAuth/JSON:API module setup
- Add README.md with full setup and configuration guide
- Update nginx/Dockerfile and nginx.conf.template for cms. subdomain
- Update drupal/Dockerfile PHP-FPM build args
- Gitignore **/.vscode/ to prevent IDE workspace files from being tracked
This commit is contained in:
rnsrk 2026-03-30 11:14:17 +02:00
parent 71a8dac389
commit f8b8f53d54
85 changed files with 7802 additions and 17 deletions

View file

@ -0,0 +1,57 @@
"use client"
import { ObfuscatedEmail } from "@/components/obfuscated-email"
import { ObfuscatedAddress } from "@/components/obfuscated-address"
interface ImprintBodyProps {
html: string
}
/**
* Renders imprint HTML with {email} and {address} placeholders replaced by
* ObfuscatedEmail and ObfuscatedAddress components.
*/
export function ImprintBody({ html }: ImprintBodyProps) {
const placeholderRegex = /\{(email|address)\}/g
const parts: (string | React.ReactNode)[] = []
let lastIndex = 0
let match
let key = 0
while ((match = placeholderRegex.exec(html)) !== null) {
const before = html.slice(lastIndex, match.index)
if (before) {
parts.push(
<span
key={`html-${key++}`}
style={{ display: "contents" }}
dangerouslySetInnerHTML={{ __html: before }}
/>
)
}
if (match[1] === "email") {
parts.push(
<ObfuscatedEmail
key={`email-${key++}`}
className="text-emerald-600 outline-none transition-colors hover:text-emerald-500 focus-visible:ring-2 focus-visible:ring-emerald-500 focus-visible:ring-offset-2"
/>
)
} else {
parts.push(<ObfuscatedAddress key={`addr-${key++}`} />)
}
lastIndex = match.index + match[0].length
}
const after = html.slice(lastIndex)
if (after) {
parts.push(
<span
key={`html-${key++}`}
style={{ display: "contents" }}
dangerouslySetInnerHTML={{ __html: after }}
/>
)
}
return <>{parts}</>
}