From df5373adbca1fc038d600cda76fdf03d0aa70bd6 Mon Sep 17 00:00:00 2001 From: starmen1265 Date: Sun, 15 Feb 2026 18:56:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=9F=A5=E8=AF=86=E5=BA=93?= =?UTF-8?q?=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 列表页改进: - 显示元数据标题而非文件名 - 显示作者、发布时间、平台 - 显示正文概述前两行 - 根据平台显示图标 文章页改进: - 过滤 YAML front matter - 只显示正文内容 --- dashboard.php | 134 +++++++++++++++++++++++++++++++++++++------------- style.css | 40 +++++++++------ view.php | 40 ++++++++++++--- 3 files changed, 160 insertions(+), 54 deletions(-) diff --git a/dashboard.php b/dashboard.php index ff67740..d48692c 100644 --- a/dashboard.php +++ b/dashboard.php @@ -9,6 +9,66 @@ $docDir = getUserDocDir($username); // 搜索关键词 $search = trim($_GET['q'] ?? ''); +// 解析 Markdown 文件的 YAML front matter +function parseMarkdownWithMeta($filePath) { + $content = file_get_contents($filePath); + $meta = [ + 'title' => basename($filePath), + 'author' => '', + 'date' => '', + 'platform' => '', + 'url' => '', + 'summary' => '' + ]; + + // 解析 YAML front matter + if (preg_match('/^---\s*\n(.*?)\n---\s*\n(.*)$/s', $content, $matches)) { + $yaml = $matches[1]; + $body = $matches[2]; + + // 解析 YAML 字段 + if (preg_match('/^title:\s*["\']?(.+?)["\']?\s*$/m', $yaml, $m)) { + $meta['title'] = trim($m[1], '"\''); + } + if (preg_match('/^author:\s*(.+?)\s*$/m', $yaml, $m)) { + $meta['author'] = trim($m[1]); + } + if (preg_match('/^date:\s*(.+?)\s*$/m', $yaml, $m)) { + $meta['date'] = trim($m[1]); + } + if (preg_match('/^platform:\s*(.+?)\s*$/m', $yaml, $m)) { + $meta['platform'] = trim($m[1]); + } + if (preg_match('/^url:\s*(.+?)\s*$/m', $yaml, $m)) { + $meta['url'] = trim($m[1]); + } + + // 提取正文概述(前两行非空内容) + $lines = preg_split('/\r?\n/', trim($body)); + $summaryLines = []; + foreach ($lines as $line) { + $line = trim($line); + if (empty($line) || strpos($line, '##') === 0) continue; + $summaryLines[] = $line; + if (count($summaryLines) >= 2) break; + } + $meta['summary'] = implode(' ', $summaryLines); + } else { + // 没有 front matter,从正文提取 + $lines = preg_split('/\r?\n/', trim($content)); + $summaryLines = []; + foreach ($lines as $line) { + $line = trim($line); + if (empty($line) || strpos($line, '#') === 0) continue; + $summaryLines[] = $line; + if (count($summaryLines) >= 2) break; + } + $meta['summary'] = implode(' ', $summaryLines); + } + + return $meta; +} + // 递归获取文档列表 $documents = []; @@ -24,10 +84,8 @@ function scanDirectory($dir, $baseDir, $search) { $relativePath = str_replace($baseDir . '/', '', $fullPath); if (is_dir($fullPath)) { - // 递归扫描子目录 $docs = array_merge($docs, scanDirectory($fullPath, $baseDir, $search)); } elseif (is_file($fullPath)) { - // 只处理 .md 和 .txt 文件 $ext = strtolower(pathinfo($item, PATHINFO_EXTENSION)); if (!in_array($ext, ['md', 'txt', 'markdown'])) continue; @@ -36,21 +94,26 @@ function scanDirectory($dir, $baseDir, $search) { // 搜索过滤 if ($search) { $searchLower = mb_strtolower($search); - $titleLower = mb_strtolower($item); $contentLower = mb_strtolower($content); - if (strpos($titleLower, $searchLower) === false && - strpos($contentLower, $searchLower) === false) { + if (strpos($contentLower, $searchLower) === false) { continue; } } + // 解析元数据 + $meta = parseMarkdownWithMeta($fullPath); + $docs[] = [ 'name' => $item, 'path' => $relativePath, 'folder' => dirname($relativePath) === '.' ? '' : dirname($relativePath), 'size' => filesize($fullPath), 'mtime' => filemtime($fullPath), - 'preview' => mb_substr(strip_tags($content), 0, 200) + 'title' => $meta['title'], + 'author' => $meta['author'], + 'date' => $meta['date'], + 'platform' => $meta['platform'], + 'summary' => $meta['summary'] ]; } } @@ -59,21 +122,32 @@ function scanDirectory($dir, $baseDir, $search) { $documents = scanDirectory($docDir, $docDir, $search); -// 按文件夹分组,然后按修改时间排序 +// 按日期排序(新文件在前) usort($documents, function($a, $b) { - // 先按文件夹排序 - if ($a['folder'] !== $b['folder']) { - return strcmp($a['folder'], $b['folder']); + // 优先按日期排序 + if ($a['date'] && $b['date']) { + return strcmp($b['date'], $a['date']); } - // 同一文件夹按修改时间排序(新文件在前) + // 其次按修改时间 return $b['mtime'] - $a['mtime']; }); + +// 平台图标映射 +function getPlatformIcon($platform) { + $icons = [ + 'bilibili' => '📺', + 'youtube' => '▶️', + 'zhihu' => '💡', + 'wechat' => '💬', + ]; + return $icons[$platform] ?? '📄'; +} ?> - + 知识库 - <?php echo htmlspecialchars($username); ?> @@ -115,34 +189,26 @@ usort($documents, function($a, $b) { - -
- 📁 -
- + -
📄
+
-
+
- KB · - - - · 📁 + + 👤 + + + 📅 + + + 🏷️
-
...
+ +
150 ? '...' : ''; ?>
+
diff --git a/style.css b/style.css index 4d4172b..5d27123 100644 --- a/style.css +++ b/style.css @@ -542,33 +542,45 @@ body::after { z-index: 1; } -.doc-name { - font-size: 16px; +.doc-title { + font-size: 17px; font-weight: 600; color: var(--text-primary); - margin-bottom: 6px; - font-family: 'JetBrains Mono', monospace; + margin-bottom: 8px; + line-height: 1.4; } .doc-meta { font-size: 12px; color: var(--text-muted); - margin-bottom: 8px; + margin-bottom: 10px; + display: flex; + flex-wrap: wrap; + gap: 12px; font-family: 'JetBrains Mono', monospace; } -.doc-meta .size, -.doc-meta .date { - opacity: 0.8; +.doc-meta .meta-author, +.doc-meta .meta-date, +.doc-meta .meta-platform { + display: inline-flex; + align-items: center; + gap: 4px; +} + +.doc-summary { + font-size: 13px; + color: var(--text-secondary); + line-height: 1.6; + opacity: 0.85; +} + +.doc-name { + display: none; } .doc-preview { - font-size: 13px; - color: var(--text-secondary); - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - line-height: 1.5; + display: none; } .empty { diff --git a/view.php b/view.php index d4e047b..b886cdd 100644 --- a/view.php +++ b/view.php @@ -10,14 +10,13 @@ $docDir = getUserDocDir($username); $file = $_GET['file'] ?? ''; $search = $_GET['q'] ?? ''; -// 安全检查:防止目录遍历攻击(允许子目录,但不能跳出用户目录) +// 安全检查 if (empty($file) || strpos($file, '..') !== false) { die('无效的文件名'); } $filePath = $docDir . '/' . $file; -// 确保文件在用户目录内 $realPath = realpath($filePath); $realDocDir = realpath($docDir); if ($realPath === false || strpos($realPath, $realDocDir) !== 0) { @@ -30,9 +29,40 @@ if (!file_exists($filePath)) { $content = file_get_contents($filePath); +// 解析元数据 +$title = basename($file); +$meta = [ + 'title' => $title, + 'author' => '', + 'date' => '', + 'platform' => '' +]; + +// 提取并移除 YAML front matter +if (preg_match('/^---\s*\n(.*?)\n---\s*\n(.*)$/s', $content, $matches)) { + $yaml = $matches[1]; + $content = $matches[2]; + + // 解析元数据(用于页面标题) + if (preg_match('/^title:\s*["\']?(.+?)["\']?\s*$/m', $yaml, $m)) { + $title = trim($m[1], '"\''); + $meta['title'] = $title; + } + if (preg_match('/^author:\s*(.+?)\s*$/m', $yaml, $m)) { + $meta['author'] = trim($m[1]); + } + if (preg_match('/^date:\s*(.+?)\s*$/m', $yaml, $m)) { + $meta['date'] = trim($m[1]); + } + if (preg_match('/^platform:\s*(.+?)\s*$/m', $yaml, $m)) { + $meta['platform'] = trim($m[1]); + } +} + // 简单的 Markdown 转换 function markdownToHtml($text) { // 标题 + $text = preg_replace('/^#### (.*$)/m', '

$1

', $text); $text = preg_replace('/^### (.*$)/m', '

$1

', $text); $text = preg_replace('/^## (.*$)/m', '

$1

', $text); $text = preg_replace('/^# (.*$)/m', '

$1

', $text); @@ -71,8 +101,6 @@ if ($search) { $htmlContent = highlightSearch($htmlContent, $search); } -// 获取文件名(不含路径) -$displayName = basename($file); $folder = dirname($file) !== '.' ? dirname($file) : ''; ?> @@ -80,7 +108,7 @@ $folder = dirname($file) !== '.' ? dirname($file) : ''; - <?php echo htmlspecialchars($displayName); ?> - 知识库 + <?php echo htmlspecialchars($title); ?> - 知识库 @@ -89,7 +117,7 @@ $folder = dirname($file) !== '.' ? dirname($file) : ''; ← 返回列表 -

+

📁