Kurzfassung: Platzieren Sie eine docinfo.html im Dokumentordner Ihres adoc Studio Projekts und setzen Sie :docinfo: shared in einer Attribut-Datei, die ganz oben in der Projekt-Seitenleiste steht. Der Inhalt der docinfo.html wird in den <head> jeder exportierten HTML-Seite eingefügt – nutzen Sie JavaScript, um Navbar, Footer und andere Elemente dynamisch in den Body zu injizieren.
Wenn Sie AsciiDoc-Dokumentation als HTML für Ihre Website exportieren, möchten Sie oft, dass sie sich wie ein nativer Teil Ihrer Seite anfühlt – komplett mit Navigation, Footer und einheitlichem Styling.
Der docinfo.html-Mechanismus in AsciiDoc bietet genau diese Möglichkeit. In diesem Artikel zeigen wir, wie wir das adoc Studio Manual in die Hauptwebsite integriert haben.
Grundlagen
Bevor wir uns mit docinfo befassen, sollten wir verstehen, wie der Website-Export von adoc Studio standardmäßig strukturiert ist. Dieses Wissen ist essenziell für eine erfolgreiche Integration.
Die Standard-HTML-Struktur
Wenn Sie Dokumentation als HTML für die Website exportieren, generiert adoc Studio Seiten mit einer spezifischen Struktur:
<body data-is-website>
<nav class="home">...</nav> <!-- Breadcrumb/Home-Navigation -->
<nav class="search">...</nav> <!-- Suchergebnis-Panel -->
<nav class="search-toggle">...</nav> <!-- Such-Button -->
<nav class="language">...</nav> <!-- Sprachwechsler -->
<main>...</main> <!-- Dokumentinhalt -->
<nav class="toc">...</nav> <!-- Inhaltsverzeichnis -->
</body>Das body-Element verwendet CSS Grid für das Layout und enthält das data-is-website-Attribut, das website-spezifisches Styling aktiviert.
Eingebaute Navigationselemente
adoc Studio bietet mehrere Navigationselemente standardmäßig an:
| Element | Klasse | Zweck |
|---|---|---|
| Home-Navigation | nav.home |
Breadcrumb-Pfad zur Dokumentationswurzel |
| Such-Panel | nav.search |
Zeigt Suchergebnisse an |
| Such-Toggle | nav.search-toggle |
Button zum Öffnen/Schließen der Suche |
| Sprachwechsler | nav.language |
Wechsel zwischen Sprachversionen |
| Inhaltsverzeichnis | nav.toc |
Dokumentnavigation in der Seitenleiste |
Diese Elemente sind standardmäßig am oberen Rand der Seite positioniert und dienen als primäre Navigation für die Dokumentation.
Warum für Website-Integration reorganisieren?
Bei der Integration von Dokumentation in eine Website möchten Sie typischerweise eine Hauptnavigationsleiste ganz oben hinzufügen – dieselbe Navbar, die auf Ihrer gesamten Website verwendet wird. Das erzeugt ein Problem:
- Die Standard-Nav-Elemente belegen die obere Position
- Ihre Site-Navbar muss ebenfalls oben sein
- Visuelle Hierarchie erfordert die Hauptnavbar zuerst, dann dokumentationsspezifische Navigation
Die Lösung ist eine SubNav – eine sekundäre Navigationsleiste unterhalb Ihrer Hauptnavbar, die die reorganisierten Dokumentationsnavigationselemente enthält.
┌─────────────────────────────────────────┐
│ Haupt-Site-Navbar (injiziert) │ ← Ihre Website-Navigation
├─────────────────────────────────────────┤
│ SubNav: Home | Suche | Sprache │ ← Reorganisierte Doc-Elemente
├─────────────────────────────────────────┤
│ Hauptinhalt │ TOC-Sidebar │
│ │ │
└─────────────────────────────────────────┘Dieser Ansatz bewahrt alle eingebauten Funktionen (Suche, Sprachwechsel, Breadcrumbs) und integriert sich nahtlos in das Design Ihrer Website.
Doch wie fügen wir diese eigene Navigation hinzu? Die Lösung ist eine docinfo-Datei.
Was ist docinfo?
Der docinfo-Mechanismus in AsciiDoc ermöglicht es, benutzerdefinierten Inhalt in Ihre exportierten HTML-Dokumente einzufügen. Eine docinfo.html-Datei wird automatisch am Ende des <head>-Bereichs jeder exportierten Seite eingefügt – ideal für Meta-Tags, Scripts und Stylesheets. Wie wir in diesem Artikel zeigen, können Sie JavaScript im Head verwenden, um Inhalte an beliebiger Stelle im Dokument einzufügen.
Private vs. Shared Docinfo
AsciiDoc unterscheidet zwischen zwei Arten von docinfo-Dateien:
Private docinfo – Nach Ihrem Dokument benannt:
mein-dokument.adoc
mein-dokument-docinfo.html ← Nur für dieses DokumentShared docinfo – Wird von allen Dokumenten im Ordner verwendet:
docinfo.html ← Geteilt von allen .adoc-Dateien
kapitel1.adoc
kapitel2.adocFür Dokumentationsprojekte ist shared docinfo typischerweise die bessere Wahl, da Sie eine einheitliche Navigation und Styling über alle Seiten hinweg wünschen.
Docinfo in Ihrem Dokument aktivieren
Um die docinfo-Verarbeitung zu aktivieren, fügen Sie das :docinfo:-Attribut zu Ihrem Dokumentkopf hinzu:
= Meine Dokumentation
:docinfo: shared
Dies ist mein Dokumentinhalt...Das :docinfo:-Attribut akzeptiert diese Werte:
| Wert | Verhalten |
|---|---|
shared |
Verwendet docinfo.html (geteilte Datei) |
private |
Verwendet {docname}-docinfo.html (dokumentspezifisch) |
shared-head |
Nur docinfo.html für Head |
private-head |
Nur {docname}-docinfo.html für Head |
shared,private |
Sowohl geteilte als auch private Dateien |
Für Website-Integration verwenden Sie:
:docinfo: sharedWeitere Docinfo-Attribute
Neben :docinfo: gibt es zwei weitere Attribute zur Feinsteuerung:
| Attribut | Werte | Beschreibung |
|---|---|---|
:docinfodir: |
Verzeichnispfad | Speicherort der docinfo-Dateien. Standard ist das Verzeichnis der Quelldatei. |
:docinfosubs: |
Komma-getrennte Substitutionen | AsciiDoc-Substitutionen, die auf den docinfo-Inhalt angewendet werden. Standard: attributes |
Mit :docinfosubs: können Sie steuern, welche AsciiDoc-Ersetzungen im docinfo-Inhalt durchgeführt werden – z.B. attributes für Attribut-Ersetzung oder specialchars für Sonderzeichen.
Docinfo in adoc Studio einbinden
In adoc Studio platzieren Sie die docinfo.html-Datei im Dokumentordner Ihres Projekts neben Ihren .adoc-Dateien:
Manual.ads/
├── Manual/
│ ├── docinfo.html ← Geteilte docinfo-Datei
│ ├── attributes.adoc ← Hat :docinfo: shared (muss ganz oben stehen!)
│ ├── chapter1.adoc
│ ├── chapter2.adoc
│ └── ...Wichtig: Das Attribut :docinfo: shared muss oberhalb der H1-Titelzeile (=) stehen, damit es im Dokumentenkopf definiert ist und für alle Dokumente gilt.
Empfohlene Struktur:
Learn.ads/
├── Learn/
│ ├── start.adoc ← Attribut-Datei (ganz oben in der Seitenleiste!)
│ ├── docinfo.html
│ ├── intro.de.adoc
│ ├── chapter1.de.adoc
│ └── ...Die start.adoc enthält nur Attribute:
// Shared attributes for all Learn documents
:docinfo: shared
:icons: fontWenn Sie nach HTML exportieren, bindet adoc Studio den docinfo-Inhalt automatisch in jede generierte Seite ein.
Die Grundstruktur einer docinfo.html
Eine docinfo.html für Website-Integration enthält typischerweise drei Teile:
1. CSS-Links
Laden externer Stylesheets für einheitliches Styling:
<link rel="stylesheet" href="/assets/css/site.css">2. HTML-Templates
Definition der zu injizierenden Elemente als JavaScript-Strings:
const navbarHTML = '<nav class="nav">...</nav>';
const footerHTML = '<footer class="footer">...</footer>';3. JavaScript-Logik
Injektion und Initialisierung der Elemente beim Laden der Seite:
document.addEventListener('DOMContentLoaded', function() {
document.body.insertAdjacentHTML('afterbegin', navbarHTML);
document.body.insertAdjacentHTML('beforeend', footerHTML);
});Mehrsprachigkeit einrichten
Spracherkennung
Für mehrsprachige Dokumentation müssen Sie die aktuelle Sprache erkennen, um die korrekten Übersetzungen anzuzeigen. Beim Website-Export von adoc Studio ist die Sprache im URL-Pfad eingebettet:
- Deutsch:
/help/Manual/de/page.html - Englisch:
/help/Manual/en/page.html
Die Struktur ist: /{Zielordner}/{Projektname}/{Sprache}/page.html – wobei help der Ordner auf dem Webserver ist, in den das adoc Studio Projekt Manual exportiert wurde.
So erkennen Sie die Sprache:
const path = window.location.pathname;
const manualLangMatch = path.match(/\/Manual\/(de|en)\//);
let lang = 'en'; // Standard
if (manualLangMatch) {
lang = manualLangMatch[1]; // 'de' oder 'en'
}Dieselbe docinfo.html für mehrere Projekte
Wenn Sie mehrere AsciiDoc-Projekte haben (z.B. ein Manual und einen Lernpfad), können Sie dieselbe docinfo.html für alle verwenden. Kopieren Sie die Datei einfach in jeden Projektordner.
Damit die Spracherkennung und der Sprachwechsler für alle Projekte funktionieren, müssen Sie die Pfad-Erkennung erweitern:
var path = window.location.pathname;
// Erkennung für Manual UND Learn
var isManualPage = path.includes('/Manual/');
var isLearnPage = path.includes('/learn/');
var manualLangMatch = path.match(/\/Manual\/(de|en)\//);
var learnLangMatch = path.match(/\/learn\/(de|en)\//);
// Sprache ermitteln
var lang;
if (isManualPage && manualLangMatch) {
lang = manualLangMatch[1];
} else if (isLearnPage && learnLangMatch) {
lang = learnLangMatch[1];
} else {
lang = (path.startsWith('/de/') || path === '/de') ? 'de' : 'en';
}Für den Sprachwechsler müssen Sie ebenfalls beide Pfad-Typen berücksichtigen:
var enUrl, deUrl;
if (isManualPage && manualLangMatch) {
var basePath = path.match(/^(.*\/Manual\/)/);
if (basePath) {
enUrl = basePath[1] + 'en/index.html';
deUrl = basePath[1] + 'de/index.html';
}
} else if (isLearnPage && learnLangMatch) {
var basePath = path.match(/^(.*\/learn\/)/);
if (basePath) {
enUrl = basePath[1] + 'en/index.html';
deUrl = basePath[1] + 'de/index.html';
}
}Tipp: Bei lokalisierten Ordnernamen (z.B. deutsche Ordner heißen anders als englische) ist es oft einfacher, beim Sprachwechsel zur Index-Seite der jeweiligen Sprache zu wechseln, statt die exakte Seite zu übersetzen.
Übersetzungen verwalten
Für die Lokalisierung gibt es zwei Ansätze: manuell (eingebettete Übersetzungen) oder automatisiert (API-basiert). Beide haben ihre Vor- und Nachteile.
Ansatz 1: Eingebettete Übersetzungen (Manuell)
Der einfachste Ansatz ist, alle Übersetzungen direkt in der docinfo.html zu speichern:
var translations = {
de: {
'nav.features': 'Funktionen',
'nav.pricing': 'Preise',
'footer.newsletter': 'Newsletter',
'footer.subscribe': 'Abonnieren'
},
en: {
'nav.features': 'Features',
'nav.pricing': 'Pricing',
'footer.newsletter': 'Newsletter',
'footer.subscribe': 'Subscribe'
}
};
// Hilfsfunktion
var t = function(key) {
return translations[lang][key] || key;
};| Vorteile | Nachteile |
|---|---|
| Funktioniert offline | Übersetzungen müssen manuell synchron gehalten werden |
| Keine Server-Abhängigkeit | Doppelte Pflege wenn Website bereits Übersetzungssystem hat |
| Einfach zu verstehen |
Ansatz 2: Übersetzungen per API laden (Automatisiert)
Wenn Ihre Website bereits ein Übersetzungssystem hat (z.B. Kirby CMS Sprachdateien), können Sie diese per API teilen:
1. API-Endpoint erstellen (/api/translations.php):
<?php
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
$lang = $_GET['lang'] ?? 'en';
$allowedLangs = ['de', 'en'];
if (!in_array($lang, $allowedLangs)) {
http_response_code(400);
exit;
}
$langFile = __DIR__ . '/../site/languages/' . $lang . '.php';
$langData = require $langFile;
echo json_encode($langData['translations'] ?? []);2. In der docinfo.html Übersetzungen laden:
async function loadTranslations() {
try {
var response = await fetch('/api/translations.php?lang=' + lang);
if (!response.ok) throw new Error('API-Fehler');
return await response.json();
} catch (err) {
console.error('Fallback zu eingebetteten Übersetzungen');
// Fallback-Übersetzungen zurückgeben
return {
'nav.features': lang === 'de' ? 'Funktionen' : 'Features',
'nav.pricing': lang === 'de' ? 'Preise' : 'Pricing'
};
}
}
async function renderUI() {
var translations = await loadTranslations();
var t = function(key) { return translations[key] || key; };
// HTML-Templates mit Übersetzungen bauen...
}| Vorteile | Nachteile |
|---|---|
| Single Source of Truth für Übersetzungen | Erfordert Netzwerkzugriff |
| Keine Doppelpflege | API muss deployed sein |
| Änderungen automatisch synchron |
Unsere Empfehlung: Für kleinere Projekte ist Ansatz 1 (eingebettet) ausreichend. Für größere Projekte mit bestehendem Übersetzungssystem empfehlen wir Ansatz 2 (API) mit Fallback-Übersetzungen für den Offline-Fall.
Template-Strings in docinfo.html
Wichtig: AsciiDoc interpretiert {variableName} als Attribute. Verwenden Sie daher String-Konkatenation statt JavaScript Template-Literals:
// FALSCH - AsciiDoc entfernt {lang}:
var url = `/api?lang=${lang}`;
// RICHTIG - String-Konkatenation:
var url = '/api?lang=' + lang;Dann nutzen Sie die Übersetzungen in Ihren Templates:
var navbarHTML = '' +
'<nav class="nav">' +
' <a href="#features">' + t('nav.features') + '</a>' +
' <a href="#pricing">' + t('nav.pricing') + '</a>' +
'</nav>';Website-Elemente integrieren
Eine Navigationsleiste einfügen
Die Navbar sollte ganz am Anfang des Body eingefügt werden:
const navbarHTML = `
<nav class="nav" id="site-nav">
<div class="container">
<a href="/" class="nav__logo">
<img src="/assets/images/logo.png" alt="Logo">
</a>
<ul class="nav__links">
<li><a href="/#features">${t('nav.features')}</a></li>
<li><a href="/#pricing">${t('nav.pricing')}</a></li>
</ul>
</div>
</nav>`;
document.body.insertAdjacentHTML('afterbegin', navbarHTML);Eingebaute Elemente in eine SubNav reorganisieren
Jetzt kommt der entscheidende Schritt: Die eingebauten Navigationselemente in eine SubNav verschieben, die unterhalb Ihrer Hauptnavbar sitzt. Dies bewahrt alle Funktionen und etabliert gleichzeitig die korrekte visuelle Hierarchie.
Warum dieser Schritt notwendig ist
Wenn Sie eine Navbar am Anfang des Body injizieren, bleiben die eingebauten Elemente (nav.home, nav.search-toggle, nav.language) an ihren ursprünglichen Positionen – was jetzt unterhalb Ihrer Navbar aber oberhalb des Hauptinhalts ist. Ohne Reorganisation hätten Sie:
- Ihre Navbar oben
- Zufällige Navigationselemente dazwischen
- Den Hauptinhalt
Durch das Verschieben dieser Elemente in einen strukturierten SubNav-Container schaffen Sie eine saubere, organisierte Oberfläche.
Den SubNav-Container erstellen
Erstellen Sie zuerst einen Container-Div und positionieren Sie ihn direkt nach Ihrer Hauptnavbar:
// SubNav-Container erstellen
const docSubnav = document.createElement('div');
docSubnav.id = 'doc-subnav';
document.getElementById('site-nav').insertAdjacentElement('afterend', docSubnav);Eingebaute Elemente verschieben
Verschieben Sie nun jedes eingebaute Element in die SubNav. Die Reihenfolge ist wichtig – ordnen Sie sie logisch an:
// Breadcrumb/Home-Navigation verschieben
const navHome = document.querySelector('body > nav.home');
if (navHome) {
docSubnav.appendChild(navHome);
}
// Such-Toggle-Button verschieben
const navSearchToggle = document.querySelector('body > nav.search-toggle');
if (navSearchToggle) {
docSubnav.appendChild(navSearchToggle);
}
// Sprachwechsler verschieben
const navLanguage = document.querySelector('body > nav.language');
if (navLanguage) {
docSubnav.appendChild(navLanguage);
}Suchfunktionalität bewahren
Der Such-Toggle-Button benötigt einen Click-Handler, um das Such-Panel ein-/auszublenden:
if (navSearchToggle) {
navSearchToggle.addEventListener('click', function() {
const navSearch = document.querySelector('nav.search');
if (navSearch) {
navSearch.classList.toggle('is-active');
}
});
}Einen Footer hinzufügen
Der Footer sollte am Ende des Body angehängt werden:
const footerHTML = `
<footer class="footer">
<div class="container">
<!-- Ihr Footer-Inhalt -->
</div>
</footer>`;
document.body.insertAdjacentHTML('beforeend', footerHTML);Einen Sprachwechsler implementieren
Damit der Sprachwechsler innerhalb des Manuals korrekt funktioniert, müssen Sie das Sprachsegment in der URL austauschen:
let enUrl, deUrl;
if (path.includes('/Manual/')) {
// /Manual/de/ ↔ /Manual/en/ tauschen
enUrl = path.replace(/\/Manual\/de\//, '/Manual/en/');
deUrl = path.replace(/\/Manual\/en\//, '/Manual/de/');
}
const langSwitcherHTML = `
<div class="lang-switcher">
<a href="${enUrl}" class="${lang === 'en' ? 'active' : ''}">EN</a>
<a href="${deUrl}" class="${lang === 'de' ? 'active' : ''}">DE</a>
</div>`;In Aktion sehen: Erkunden Sie unseren Lernpfad oder das adoc Studio Handbuch, um zu sehen, wie wir Navbar und Footer mit docinfo integriert haben.
Fazit
Der docinfo.html-Mechanismus bietet eine leistungsstarke Möglichkeit, AsciiDoc-Dokumentation nahtlos in Ihre Website zu integrieren. Je nach Projektgröße können Sie wählen zwischen:
- Manuell: Selbstständige docinfo.html mit eingebetteten Übersetzungen – ideal für kleinere Projekte
- Automatisiert: API-basierte Übersetzungen und Shared JavaScript – ideal für größere Projekte mit bestehendem CMS
Denken Sie daran: AsciiDoc interpretiert {...} als Attribute. Verwenden Sie daher String-Konkatenation (' + variable + ') statt Template-Literals in Ihren JavaScript-Strings.
Der Schlüssel ist, docinfo.html als Brücke zwischen Ihrer statischen Dokumentation und Ihrer dynamischen Website zu betrachten – damit beide als zusammenhängendes Ganzes funktionieren.