121 行
5.1 KiB
PHP
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>
|