文件
parlz-domain/doc/index.php
T

121 行
5.1 KiB
PHP

<?php
$baseDir = __DIR__ . '/md';
$fileParam = isset($_GET['file']) ? trim($_GET['file']) : '';
$isAjax = isset($_GET['_ajax']);
if (empty($fileParam)) {
$files = glob($baseDir . '/*.md');
if ($files) {
usort($files, function($a, $b) {
return filemtime($b) - filemtime($a);
});
$fileParam = 'md/' . basename($files[0]);
} else {
$fileParam = 'md/index.md';
}
}
$fileParam = str_replace(['..', '/\\', "\0", '\\'], '', $fileParam);
if (!preg_match('/^md\/[a-zA-Z0-9_\-\x{4e00}-\x{9fff}]+(\/[a-zA-Z0-9_\-\x{4e00}-\x{9fff}]+)*\.md$/u', $fileParam)) {
if (preg_match('/^[a-zA-Z0-9_\-\x{4e00}-\x{9fff}]+(\/[a-zA-Z0-9_\-\x{4e00}-\x{9fff}]+)*\.md$/u', $fileParam)) {
$fileParam = '/doc/md/' . $fileParam;
} else {
$fileParam = '';
}
}
$mdFile = __DIR__ . '/' . $fileParam;
$content = '';
$title = 'Docs';
$currentFile = $fileParam;
$pathParts = explode('/', $fileParam);
$pageName = basename($fileParam, '.md');
$folderName = (count($pathParts) > 2) ? $pathParts[1] : '';
$title = ucfirst($pageName);
if (!empty($fileParam) && file_exists($mdFile) && is_file($mdFile)) {
$rawContent = file_get_contents($mdFile);
} else {
$rawContent = '';
$title = '未找到';
}
if ($isAjax) {
echo $rawContent;
exit;
}
function getDirStructure($dir, $base = '') {
$items = [];
$entries = scandir($dir);
foreach ($entries as $entry) {
if ($entry === '.' || $entry === '..') continue;
$path = $dir . '/' . $entry;
$rel = $base ? $base . '/' . $entry : $entry;
if (is_dir($path)) {
$items[] = ['type' => 'dir', 'name' => $entry, 'path' => $rel, 'children' => getDirStructure($path, $rel)];
} elseif (pathinfo($path, PATHINFO_EXTENSION) === 'md') {
$items[] = ['type' => 'file', 'name' => $entry, 'path' => $rel];
}
}
return $items;
}
$tree = getDirStructure($baseDir);
function renderTree($items, $currentFile) {
$html = '<ul>';
foreach ($items as $item) {
if ($item['type'] === 'dir') {
$html .= '<li class="folder"><span class="folder-toggle"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg> ' . htmlspecialchars($item['name']) . '</span>';
$html .= renderTree($item['children'], $currentFile);
$html .= '</li>';
} else {
$active = $currentFile === 'md/' . $item['path'] ? 'active' : '';
$html .= '<li class="file ' . $active . '"><a href="/doc/?file=md/' . $item['path'] . '"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg> ' . htmlspecialchars($item['name']) . '</a></li>';
}
}
$html .= '</ul>';
return $html;
}
?>
<!DOCTYPE html>
<html lang="zh-CN" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($title); ?> - Parlz Domains Docs</title>
<link rel="stylesheet" href="/doc/style.css">
</head>
<body>
<div class="layout">
<aside class="sidebar">
<div class="sidebar-header">
<h1>文档列表</h1>
<button class="theme-toggle" id="themeToggle">
<svg class="sun" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
<svg class="moon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
</button>
</div>
<div class="search-box">
<input type="text" id="searchInput" placeholder="搜索任何文档...">
</div>
<nav class="nav-tree" id="navTree">
<?php echo renderTree($tree, $currentFile); ?>
</nav>
</aside>
<main class="content">
<div class="mobile-header">
<button class="menu-toggle" id="menuToggle">☰</button>
<span class="mobile-title">Parlz Domains Docs</span>
<button class="theme-toggle" id="mobileThemeToggle">
<svg class="sun" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
<svg class="moon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
</button>
</div>
<div class="markdown-body" id="markdownBody">
<?php if ($rawContent): ?>
<?php echo $rawContent; ?>
<?php else: ?>
<p>暂无文档</p>
<?php endif; ?>
</div>
</main>
<div class="overlay" id="overlay"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="/doc/script.js"></script>
</body>
</html>