添加标签和完整元数据显示

列表页:
- 显示标签(最多5个)
- 显示作者、发布时间、平台、时长
- 显示源链接
- 显示类型(视频/文章)
- 平台颜色徽章

文章页:
- 新增元数据卡片
- 显示所有元数据信息
- 显示所有标签
- 源链接可点击跳转
This commit is contained in:
2026-02-15 21:25:06 +08:00
parent a1598ce243
commit cd38932eb0
3 changed files with 341 additions and 53 deletions
+63 -33
View File
@@ -18,6 +18,9 @@ function parseMarkdownWithMeta($filePath) {
'date' => '',
'platform' => '',
'url' => '',
'tags' => [],
'duration' => '',
'type' => 'article',
'summary' => ''
];
@@ -42,8 +45,17 @@ function parseMarkdownWithMeta($filePath) {
if (preg_match('/^url:\s*(.+?)\s*$/m', $yaml, $m)) {
$meta['url'] = trim($m[1]);
}
if (preg_match('/^duration:\s*(.+?)\s*$/m', $yaml, $m)) {
$meta['duration'] = trim($m[1]);
$meta['type'] = 'video';
}
if (preg_match('/^tags:\s*\[(.+)\]\s*$/m', $yaml, $m)) {
$tagsStr = $m[1];
preg_match_all('/"([^"]+)"/', $tagsStr, $tagMatches);
$meta['tags'] = $tagMatches[1] ?? [];
}
// 提取正文概述(前两行非空内容)
// 提取正文概述
$lines = preg_split('/\r?\n/', trim($body));
$summaryLines = [];
foreach ($lines as $line) {
@@ -53,17 +65,6 @@ function parseMarkdownWithMeta($filePath) {
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;
@@ -91,7 +92,6 @@ function scanDirectory($dir, $baseDir, $search) {
$content = file_get_contents($fullPath);
// 搜索过滤
if ($search) {
$searchLower = mb_strtolower($search);
$contentLower = mb_strtolower($content);
@@ -100,19 +100,21 @@ function scanDirectory($dir, $baseDir, $search) {
}
}
// 解析元数据
$meta = parseMarkdownWithMeta($fullPath);
$docs[] = [
'name' => $item,
'path' => $relativePath,
'folder' => dirname($relativePath) === '.' ? '' : dirname($relativePath),
'size' => filesize($fullPath),
'mtime' => filemtime($fullPath),
'title' => $meta['title'],
'author' => $meta['author'],
'date' => $meta['date'],
'platform' => $meta['platform'],
'url' => $meta['url'],
'tags' => $meta['tags'],
'duration' => $meta['duration'],
'type' => $meta['type'],
'summary' => $meta['summary']
];
}
@@ -122,32 +124,35 @@ function scanDirectory($dir, $baseDir, $search) {
$documents = scanDirectory($docDir, $docDir, $search);
// 按日期排序(新文件在前)
// 排序
usort($documents, function($a, $b) {
// 优先按日期排序
if ($a['date'] && $b['date']) {
return strcmp($b['date'], $a['date']);
}
// 其次按修改时间
return $b['mtime'] - $a['mtime'];
});
// 平台图标映射
function getPlatformIcon($platform) {
$icons = [
'bilibili' => '📺',
'youtube' => '▶️',
'zhihu' => '💡',
'wechat' => '💬',
// 平台配置
function getPlatformInfo($platform) {
$platforms = [
'bilibili' => ['name' => 'Bilibili', 'icon' => '📺', 'color' => '#fb7299'],
'youtube' => ['name' => 'YouTube', 'icon' => '▶️', 'color' => '#ff0000'],
'zhihu' => ['name' => '知乎', 'icon' => '💡', 'color' => '#0084ff'],
'wechat' => ['name' => '微信', 'icon' => '💬', 'color' => '#07c160'],
];
return $icons[$platform] ?? '📄';
return $platforms[$platform] ?? ['name' => $platform ?: '未知', 'icon' => '📄', 'color' => '#666'];
}
// 类型图标
function getTypeIcon($type) {
return $type === 'video' ? '🎬' : '📝';
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device=device-width, initial-scale=1.0">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>知识库 - <?php echo htmlspecialchars($username); ?></title>
<link rel="stylesheet" href="style.css">
</head>
@@ -189,23 +194,48 @@ function getPlatformIcon($platform) {
<?php endif; ?>
</div>
<?php else: ?>
<?php foreach ($documents as $doc): ?>
<?php foreach ($documents as $doc):
$platformInfo = getPlatformInfo($doc['platform']);
?>
<a href="view.php?file=<?php echo urlencode($doc['path']); ?><?php echo $search ? '&q=' . urlencode($search) : ''; ?>"
class="document-card">
<div class="doc-icon"><?php echo getPlatformIcon($doc['platform']); ?></div>
<div class="doc-icon"><?php echo $platformInfo['icon']; ?></div>
<div class="doc-info">
<div class="doc-title"><?php echo htmlspecialchars($doc['title']); ?></div>
<div class="doc-header">
<span class="doc-type"><?php echo getTypeIcon($doc['type']); ?></span>
<span class="doc-title"><?php echo htmlspecialchars($doc['title']); ?></span>
</div>
<div class="doc-meta">
<?php if ($doc['author']): ?>
<span class="meta-author">👤 <?php echo htmlspecialchars($doc['author']); ?></span>
<span class="meta-item">👤 <?php echo htmlspecialchars($doc['author']); ?></span>
<?php endif; ?>
<?php if ($doc['date']): ?>
<span class="meta-date">📅 <?php echo htmlspecialchars($doc['date']); ?></span>
<span class="meta-item">📅 <?php echo htmlspecialchars($doc['date']); ?></span>
<?php endif; ?>
<?php if ($doc['platform']): ?>
<span class="meta-platform">🏷️ <?php echo htmlspecialchars($doc['platform']); ?></span>
<span class="meta-item platform-badge" style="--platform-color: <?php echo $platformInfo['color']; ?>">
<?php echo $platformInfo['name']; ?>
</span>
<?php endif; ?>
<?php if ($doc['duration']): ?>
<span class="meta-item">⏱️ <?php echo htmlspecialchars($doc['duration']); ?></span>
<?php endif; ?>
<?php if ($doc['url']): ?>
<span class="meta-item source-link" onclick="event.stopPropagation(); event.preventDefault(); window.open('<?php echo htmlspecialchars($doc['url']); ?>', '_blank');">
🔗 源链接
</span>
<?php endif; ?>
</div>
<?php if (!empty($doc['tags'])): ?>
<div class="doc-tags">
<?php foreach (array_slice($doc['tags'], 0, 5) as $tag): ?>
<span class="tag"><?php echo htmlspecialchars($tag); ?></span>
<?php endforeach; ?>
<?php if (count($doc['tags']) > 5): ?>
<span class="tag-more">+<?php echo count($doc['tags']) - 5; ?></span>
<?php endif; ?>
</div>
<?php endif; ?>
<?php if ($doc['summary']): ?>
<div class="doc-summary"><?php echo htmlspecialchars(mb_substr($doc['summary'], 0, 150)); ?><?php echo mb_strlen($doc['summary']) > 150 ? '...' : ''; ?></div>
<?php endif; ?>