index.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * Simple documentation viewer (Markdown → HTML via marked).
  5. */
  6. $docsDir = __DIR__;
  7. $docMap = [];
  8. foreach (glob($docsDir . '/*.md') ?: [] as $path) {
  9. $base = basename($path, '.md');
  10. if (preg_match('/^[A-Z0-9_]+$/', $base) !== 1) {
  11. continue;
  12. }
  13. $docMap[$base] = $path;
  14. }
  15. ksort($docMap);
  16. $requested = isset($_GET['doc']) ? (string) $_GET['doc'] : '';
  17. $activeDoc = null;
  18. $markdown = null;
  19. $pageTitle = 'Dokumentation';
  20. if ($requested !== '') {
  21. if (!isset($docMap[$requested])) {
  22. http_response_code(404);
  23. $pageTitle = 'Nicht gefunden';
  24. } else {
  25. $activeDoc = $requested;
  26. $markdown = file_get_contents($docMap[$requested]);
  27. if ($markdown === false) {
  28. http_response_code(500);
  29. $pageTitle = 'Fehler';
  30. $markdown = null;
  31. } else {
  32. $pageTitle = docTitle($activeDoc);
  33. }
  34. }
  35. }
  36. function docTitle(string $key): string
  37. {
  38. return ucwords(strtolower(str_replace('_', ' ', $key)));
  39. }
  40. function escape(string $value): string
  41. {
  42. return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
  43. }
  44. $baseHref = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'] ?? '/docs')), '/') . '/';
  45. if ($baseHref === '/') {
  46. $baseHref = '/docs/';
  47. }
  48. ?>
  49. <!DOCTYPE html>
  50. <html lang="de">
  51. <head>
  52. <meta charset="UTF-8">
  53. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  54. <title><?php echo escape($pageTitle); ?> – PSA Dokumentation</title>
  55. <link rel="stylesheet" href="<?php echo escape($baseHref); ?>assets/docs.css">
  56. </head>
  57. <body>
  58. <header class="docs-header">
  59. <div class="docs-header-inner">
  60. <a class="docs-brand" href="<?php echo escape($baseHref); ?>index.php">PSA Dokumentation</a>
  61. <a class="docs-back" href="../index.php">Zur Anwendung</a>
  62. </div>
  63. </header>
  64. <div class="docs-layout">
  65. <nav class="docs-nav" aria-label="Dokumentation">
  66. <p class="docs-nav-title">Inhalt</p>
  67. <ul>
  68. <?php foreach ($docMap as $key => $_path): ?>
  69. <li>
  70. <a href="<?php echo escape($baseHref); ?>index.php?doc=<?php echo escape($key); ?>"
  71. <?php echo $key === $activeDoc ? 'aria-current="page"' : ''; ?>>
  72. <?php echo escape(docTitle($key)); ?>
  73. </a>
  74. </li>
  75. <?php endforeach; ?>
  76. </ul>
  77. </nav>
  78. <main class="docs-main">
  79. <?php if ($requested === ''): ?>
  80. <h1>Dokumentation</h1>
  81. <p>Technische und fachliche Hinweise zum PSA-Bestellsystem.</p>
  82. <ul class="docs-index-list">
  83. <?php foreach ($docMap as $key => $_path): ?>
  84. <li>
  85. <a href="<?php echo escape($baseHref); ?>index.php?doc=<?php echo escape($key); ?>">
  86. <?php echo escape(docTitle($key)); ?>
  87. </a>
  88. </li>
  89. <?php endforeach; ?>
  90. </ul>
  91. <?php elseif ($markdown === null): ?>
  92. <h1><?php echo escape($pageTitle); ?></h1>
  93. <p>Das angeforderte Dokument ist nicht verfügbar.</p>
  94. <p><a href="<?php echo escape($baseHref); ?>index.php">Zur Übersicht</a></p>
  95. <?php else: ?>
  96. <article id="doc-content" class="markdown-body"></article>
  97. <script type="application/json" id="doc-source"><?php
  98. echo json_encode(
  99. $markdown,
  100. JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_UNESCAPED_UNICODE
  101. );
  102. ?></script>
  103. <?php endif; ?>
  104. </main>
  105. </div>
  106. <?php if ($markdown !== null): ?>
  107. <script src="<?php echo escape($baseHref); ?>assets/marked.min.js"></script>
  108. <script>
  109. (function () {
  110. var source = document.getElementById('doc-source');
  111. var target = document.getElementById('doc-content');
  112. if (!source || !target || typeof marked === 'undefined') {
  113. return;
  114. }
  115. var text = JSON.parse(source.textContent || '""');
  116. target.innerHTML = marked.parse(text, { gfm: true, breaks: false });
  117. target.querySelectorAll('a[href]').forEach(function (link) {
  118. var href = link.getAttribute('href');
  119. if (!href || /^[a-z]+:/i.test(href) || href.charAt(0) === '#') {
  120. return;
  121. }
  122. var name = href.split('/').pop().replace(/\.md$/i, '');
  123. if (/^[A-Z0-9_]+$/i.test(name)) {
  124. link.setAttribute('href', 'index.php?doc=' + encodeURIComponent(name.toUpperCase()));
  125. }
  126. });
  127. })();
  128. </script>
  129. <?php endif; ?>
  130. </body>
  131. </html>