独眼蛇front
独眼蛇
点击下载完整源码
点击文件查看代码
<?php
/**
* 项目展示 + 源码浏览(双标签底部导航)
* 标签:首页、源码
*/
// ========== 配置 ==========
define('PROJECTS_DIR', __DIR__ . '/projects');
$allowed_projects = [];
$exclude_from_zip = [
'.git', '.svn', '.DS_Store', 'Thumbs.db',
'description.txt', 'tags.txt'
];
$image_extensions = ['png', 'jpg', 'jpeg', 'gif', 'webp'];
// ========== 项目相关函数 ==========
function get_projects() {
global $image_extensions;
$projects = [];
if (!is_dir(PROJECTS_DIR)) mkdir(PROJECTS_DIR, 0755, true);
$dirs = glob(PROJECTS_DIR . '/*', GLOB_ONLYDIR);
foreach ($dirs as $dir) {
$name = basename($dir);
$description = '';
$tags = [];
$image = '';
$desc_file = $dir . '/description.txt';
if (is_file($desc_file)) $description = trim(file_get_contents($desc_file));
$tags_file = $dir . '/tags.txt';
if (is_file($tags_file)) $tags = array_map('trim', file($tags_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES));
$preferred_names = ['preview', 'screenshot', 'cover'];
$found_image = '';
foreach ($preferred_names as $base) {
foreach ($image_extensions as $ext) {
$test_file = $dir . '/' . $base . '.' . $ext;
if (is_file($test_file)) { $found_image = $test_file; break 2; }
}
}
if (!$found_image) {
$files = scandir($dir);
foreach ($files as $file) {
$ext = pathinfo($file, PATHINFO_EXTENSION);
if (in_array(strtolower($ext), $image_extensions)) {
$found_image = $dir . '/' . $file;
break;
}
}
}
if ($found_image) {
$image = str_replace(__DIR__, '', $found_image);
$image = ltrim($image, '/\\');
$image = '/' . str_replace('\\', '/', $image);
}
$mtime = filemtime($dir);
$projects[] = [
'name' => $name,
'description' => $description ?: '暂无描述',
'tags' => $tags,
'mtime' => $mtime,
'path' => $dir,
'image' => $image,
];
}
usort($projects, function($a,$b){ return $b['mtime'] - $a['mtime']; });
return $projects;
}
function add_folder_to_zip($zip, $folder, $relative_path = '', $exclude = []) {
$folder = rtrim($folder, '/\\');
$items = scandir($folder);
foreach ($items as $item) {
if ($item === '.' || $item === '..') continue;
if (in_array($item, $exclude)) continue;
$full_path = $folder . '/' . $item;
$zip_path = $relative_path ? $relative_path . '/' . $item : $item;
if (is_dir($full_path)) {
$zip->addEmptyDir($zip_path);
add_folder_to_zip($zip, $full_path, $zip_path, $exclude);
} else {
$zip->addFile($full_path, $zip_path);
}
}
}
function download_project($project_name) {
global $allowed_projects, $exclude_from_zip;
if (strpos($project_name, '..') !== false || strpos($project_name, '/') !== false || strpos($project_name, '\\') !== false) die('非法项目名');
if (!empty($allowed_projects) && !in_array($project_name, $allowed_projects)) die('项目不允许下载');
$project_dir = PROJECTS_DIR . '/' . $project_name;
if (!is_dir($project_dir)) die('项目不存在');
$tmp_zip = tempnam(sys_get_temp_dir(), 'project_') . '.zip';
$zip = new ZipArchive();
if ($zip->open($tmp_zip, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) die('无法创建 ZIP 文件');
add_folder_to_zip($zip, $project_dir, $project_name, $exclude_from_zip);
$zip->close();
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="' . $project_name . '.zip"');
header('Content-Length: ' . filesize($tmp_zip));
readfile($tmp_zip);
unlink($tmp_zip);
exit;
}
// ========== 源码浏览相关函数 ==========
function get_file_list($dir = '.', $exclude = ['.', '..', '.git', '.svn', 'node_modules', 'vendor', 'cache', 'logs', 'tmp', 'projects']) {
$files = [];
$dir = rtrim($dir, '/\\');
if (!is_dir($dir)) return $files;
$items = scandir($dir);
foreach ($items as $item) {
if (in_array($item, $exclude)) continue;
$path = $dir . '/' . $item;
if (is_dir($path)) {
$sub = get_file_list($path, $exclude);
$files = array_merge($files, $sub);
} else {
$ext = pathinfo($item, PATHINFO_EXTENSION);
if (in_array(strtolower($ext), ['php', 'html', 'css', 'js', 'txt', 'json', 'xml', 'md', 'sql'])) {
$files[] = $path;
}
}
}
sort($files);
return $files;
}
// ========== 处理下载请求 ==========
if (isset($_GET['download'])) {
download_project($_GET['download']);
exit;
}
// ========== 获取数据 ==========
$projects = get_projects();
$source_files = get_file_list('.');
$current_file = isset($_GET['file']) ? $_GET['file'] : '';
if ($current_file && strpos($current_file, '..') === false && is_file($current_file)) {
// keep
} else {
$current_file = !empty($source_files) ? $source_files[0] : '';
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>我的项目集</title>
<style>
/* ========== 全局 ========== */
* { margin:0; padding:0; box-sizing:border-box; }
body {
font-family: 'Segoe UI', 'PingFang SC', Roboto, sans-serif;
background: linear-gradient(180deg, #f7f3eb 0%, #e5edf5 30%, #dcedd8 65%, #f5edda 100%);
min-height: 100vh;
padding-bottom: 70px;
position: relative;
overflow-x: hidden;
}
.glow {
position: fixed;
border-radius: 50%;
filter: blur(120px);
pointer-events: none;
z-index: 0;
opacity: 0.5;
}
.glow-1 { width: 600px; height: 600px; background: radial-gradient(circle, rgba(200,220,240,0.6) 0%, transparent 70%); top:-100px; left:-100px; }
.glow-2 { width: 500px; height: 500px; background: radial-gradient(circle, rgba(200,230,210,0.5) 0%, transparent 70%); bottom:-50px; right:-80px; }
.glow-3 { width: 400px; height: 400px; background: radial-gradient(circle, rgba(245,220,180,0.5) 0%, transparent 70%); top:40%; left:60%; transform:translate(-50%,-50%); }
.glow-4 { width: 350px; height: 350px; background: radial-gradient(circle, rgba(210,230,245,0.4) 0%, transparent 70%); bottom:20%; left:10%; }
.app {
max-width: 600px;
margin: 0 auto;
position: relative;
z-index: 1;
padding: 16px 16px 0;
}
.page {
display: none;
animation: fadeIn 0.3s ease;
}
.page.active { display: block; }
@keyframes fadeIn { from { opacity:0; transform:translateY(10px); } to { opacity:1; transform:translateY(0); } }
/* ========== 首页 ========== */
header {
text-align: center;
padding: 20px 0 16px;
}
header h1 {
font-size: 28px;
font-weight: 700;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
header p {
color: #4a5568;
font-size: 14px;
margin-top: 4px;
background: rgba(255,255,255,0.3);
backdrop-filter: blur(4px);
padding: 4px 16px;
border-radius: 30px;
display: inline-block;
}
.projects-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
gap: 16px;
margin-top: 12px;
}
.project-card {
background: rgba(255,255,255,0.75);
backdrop-filter: blur(12px);
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0,0,0,0.06);
overflow: hidden;
border: 1px solid rgba(255,255,255,0.5);
transition: transform 0.25s;
}
.project-card:hover { transform: translateY(-4px); }
.project-card .image-wrapper {
width: 100%;
aspect-ratio: 16/9;
background: rgba(200,200,200,0.2);
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.project-card .image-wrapper img {
width: 100%;
height: 100%;
object-fit: cover;
}
.project-card .image-wrapper .placeholder {
font-size: 48px;
color: rgba(100,100,100,0.5);
}
.project-card .content {
padding: 14px 16px 14px;
}
.project-card .name {
font-size: 18px;
font-weight: 600;
color: #2d3748;
margin-bottom: 4px;
}
.project-card .description {
font-size: 14px;
color: #4a5568;
line-height: 1.5;
margin-bottom: 10px;
}
.project-card .tags {
display: flex;
flex-wrap: wrap;
gap: 4px;
margin-bottom: 10px;
}
.project-card .tags .tag {
background: rgba(235,244,255,0.7);
color: #2b6cb0;
padding: 2px 10px;
border-radius: 20px;
font-size: 12px;
}
.project-card .footer {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid rgba(200,200,200,0.3);
padding-top: 10px;
flex-wrap: wrap;
gap: 6px;
}
.project-card .footer .date {
font-size: 12px;
color: #718096;
}
.project-card .footer .download-btn {
background: #667eea;
color: #fff;
border: none;
padding: 6px 16px;
border-radius: 30px;
font-size: 13px;
font-weight: 500;
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 4px;
transition: background 0.2s;
}
.project-card .footer .download-btn:hover {
background: #5a67d8;
}
.empty-state {
text-align: center;
padding: 60px 20px;
color: rgba(100,100,100,0.7);
}
.empty-state .emoji { font-size: 48px; display:block; margin-bottom:12px; }
.empty-state .title { font-size: 20px; color:#4a5568; }
/* ========== 源码页面 ========== */
.source-container {
display: flex;
flex-direction: column;
gap: 12px;
margin-top: 12px;
}
.source-file-list {
background: rgba(255,255,255,0.6);
backdrop-filter: blur(8px);
border-radius: 12px;
padding: 12px;
max-height: 200px;
overflow-y: auto;
border: 1px solid rgba(255,255,255,0.3);
}
.source-file-list .file-item {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 10px;
border-radius: 8px;
cursor: pointer;
transition: background 0.2s;
text-decoration: none;
color: #2d3748;
font-size: 14px;
}
.source-file-list .file-item:hover,
.source-file-list .file-item.active {
background: rgba(102,126,234,0.15);
}
.source-file-list .file-item .icon { font-size: 16px; width: 24px; text-align:center; }
.source-file-list .file-item .name { flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.source-file-list .file-item .badge {
font-size: 10px;
background: rgba(0,0,0,0.08);
padding: 1px 8px;
border-radius: 10px;
color: #4a5568;
}
.source-code-view {
background: rgba(13,17,23,0.85);
backdrop-filter: blur(8px);
border-radius: 12px;
padding: 16px;
overflow: auto;
max-height: 400px;
border: 1px solid rgba(255,255,255,0.1);
color: #e6edf3;
font-family: 'JetBrains Mono', 'Consolas', monospace;
font-size: 13px;
line-height: 1.6;
white-space: pre-wrap;
word-break: break-all;
}
.source-code-view .hljs {
background: transparent !important;
color: #e6edf3 !important;
}
.source-code-view .hljs-keyword { color:#ff7b72; }
.source-code-view .hljs-string { color:#a5d6ff; }
.source-code-view .hljs-comment { color:#8b949e; font-style:italic; }
.source-code-view .hljs-function { color:#d2a8ff; }
.source-code-view .hljs-variable { color:#ffa657; }
.source-code-view .hljs-number { color:#a5d6ff; }
.source-code-view .hljs-operator { color:#ff7b72; }
.source-code-view .hljs-class { color:#ffa657; }
.source-empty {
text-align: center;
color: #8b949e;
padding: 40px 0;
}
/* ========== 底部导航(双标签) ========== */
.bottom-nav {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: rgba(255,255,255,0.85);
backdrop-filter: blur(16px);
border-top: 1px solid rgba(255,255,255,0.3);
display: flex;
justify-content: space-around;
align-items: center;
height: 64px;
z-index: 100;
padding: 0 8px;
box-shadow: 0 -4px 20px rgba(0,0,0,0.04);
}
.bottom-nav .nav-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 4px 0;
cursor: pointer;
border: none;
background: transparent;
color: #a0aec0;
font-size: 10px;
transition: color 0.2s;
gap: 2px;
text-decoration: none;
-webkit-tap-highlight-color: transparent;
outline: none;
}
.bottom-nav .nav-item .nav-icon {
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
}
.bottom-nav .nav-item .nav-icon svg {
width: 26px;
height: 26px;
fill: currentColor;
transition: fill 0.2s;
}
.bottom-nav .nav-item .nav-label {
font-size: 10px;
font-weight: 500;
letter-spacing: 0.3px;
}
.bottom-nav .nav-item.active {
color: #667eea;
}
.bottom-nav .nav-item.active .nav-icon svg {
fill: #667eea;
}
.bottom-nav .nav-item:active {
transform: scale(0.95);
}
/* ========== 移动端适配 ========== */
@media (max-width: 480px) {
.app { padding: 12px 12px 0; }
header h1 { font-size: 24px; }
.projects-grid { grid-template-columns: 1fr; }
.project-card .content { padding: 12px 14px; }
.source-file-list { max-height: 150px; }
.source-code-view { max-height: 300px; font-size: 12px; }
.bottom-nav { height: 58px; }
.bottom-nav .nav-item .nav-icon svg { width: 22px; height: 22px; }
.bottom-nav .nav-item .nav-label { font-size: 9px; }
}
@media (max-width: 380px) {
header h1 { font-size: 20px; }
.bottom-nav .nav-item .nav-icon svg { width: 20px; height: 20px; }
}
</style>
</head>
<body>
<!-- 背景光晕 -->
<div class="glow glow-1"></div>
<div class="glow glow-2"></div>
<div class="glow glow-3"></div>
<div class="glow glow-4"></div>
<div class="app">
<!-- ===== 首页(项目展示) ===== -->
<div id="page-home" class="page active">
<header>
<h1>📦 我的项目集</h1>
<p>点击下载完整源码</p>
</header>
<?php if (empty($projects)): ?>
<div class="empty-state"><span class="emoji">📁</span><div class="title">还没有项目</div><p style="margin-top:6px;">请在 projects/ 目录下创建项目文件夹</p></div>
<?php else: ?>
<div class="projects-grid">
<?php foreach ($projects as $proj): ?>
<div class="project-card">
<div class="image-wrapper">
<?php if (!empty($proj['image']) && file_exists(__DIR__ . $proj['image'])): ?>
<img src="<?= htmlspecialchars($proj['image']) ?>" alt="<?= htmlspecialchars($proj['name']) ?>" loading="lazy">
<?php else: ?>
<span class="placeholder">📂</span>
<?php endif; ?>
</div>
<div class="content">
<div class="name"><?= htmlspecialchars($proj['name']) ?></div>
<div class="description"><?= nl2br(htmlspecialchars($proj['description'])) ?></div>
<?php if (!empty($proj['tags'])): ?>
<div class="tags"><?php foreach ($proj['tags'] as $tag): ?><span class="tag"><?= htmlspecialchars($tag) ?></span><?php endforeach; ?></div>
<?php endif; ?>
<div class="footer">
<span class="date">更新于 <?= date('Y-m-d', $proj['mtime']) ?></span>
<a href="?download=<?= urlencode($proj['name']) ?>" class="download-btn">⬇️ 下载 ZIP</a>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<!-- ===== 源码 ===== -->
<div id="page-source" class="page">
<header><h1>📄 源码浏览</h1><p>点击文件查看代码</p></header>
<div class="source-container">
<div class="source-file-list">
<?php if (empty($source_files)): ?>
<div class="source-empty">没有可显示的文件</div>
<?php else: ?>
<?php foreach ($source_files as $file): ?>
<?php
$is_active = ($file === $current_file);
$ext = pathinfo($file, PATHINFO_EXTENSION);
$icon = '📄';
if ($ext === 'php') $icon = '🐘';
elseif ($ext === 'html') $icon = '🌐';
elseif ($ext === 'css') $icon = '🎨';
elseif ($ext === 'js') $icon = '⚡';
elseif ($ext === 'json') $icon = '📋';
elseif ($ext === 'md') $icon = '📖';
?>
<a href="?file=<?= urlencode($file) ?>" class="file-item <?= $is_active ? 'active' : '' ?>" data-file="<?= htmlspecialchars($file) ?>">
<span class="icon"><?= $icon ?></span>
<span class="name"><?= htmlspecialchars(basename($file)) ?></span>
<span class="badge"><?= strtoupper($ext) ?></span>
</a>
<?php endforeach; ?>
<?php endif; ?>
</div>
<div class="source-code-view" id="sourceCodeView">
<?php if (!empty($current_file) && is_file($current_file)): ?>
<?php
$ext = pathinfo($current_file, PATHINFO_EXTENSION);
if ($ext === 'php') {
ob_start();
highlight_file($current_file);
$code = ob_get_clean();
echo $code;
} else {
$content = file_get_contents($current_file);
echo '<pre style="margin:0;white-space:pre-wrap;">' . htmlspecialchars($content) . '</pre>';
}
?>
<?php else: ?>
<div class="source-empty">请从列表中选择一个文件</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
<!-- ===== 底部导航(两个标签) ===== -->
<nav class="bottom-nav" id="bottomNav">
<!-- 首页(星星图标) -->
<button class="nav-item active" data-target="page-home">
<span class="nav-icon">
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M573.44 123.7504L658.7904 296.96a66.816 66.816 0 0 0 50.2784 36.5568l191.1296 27.7504a66.56 66.56 0 0 1 37.0176 113.92l-138.24 134.8096a66.56 66.56 0 0 0-19.2 59.0848l32.6144 190.3616a66.56 66.56 0 0 1-96.8704 70.4l-170.9568-89.856a66.56 66.56 0 0 0-62.1568 0L311.4496 929.792a66.56 66.56 0 0 1-96.9216-70.4l32.6656-190.3616a66.56 66.56 0 0 0-19.2512-59.0848l-138.24-134.8096a66.56 66.56 0 0 1 36.9664-113.92l191.1296-27.7504A66.816 66.816 0 0 0 368.0768 296.96l85.4528-173.2096a66.816 66.816 0 0 1 119.9104 0z" fill="currentColor"/>
<path d="M942.6432 469.0432a65.28 65.28 0 0 0-42.4448-24.32l-191.1296-27.7504a66.816 66.816 0 0 1-50.2784-36.5568L573.44 207.2576a66.56 66.56 0 0 0-119.808 0L368.0768 380.416a66.816 66.816 0 0 1-50.2784 36.5568l-191.1296 27.7504a65.28 65.28 0 0 0-42.4448 24.32 66.8672 66.8672 0 0 0 5.4784 6.0928l138.24 134.8096a66.56 66.56 0 0 1 19.2512 59.0848l-7.0144 40.96a66.9696 66.9696 0 0 1 7.0144 42.6496l-25.6 149.8624a66.56 66.56 0 0 0 89.9584 27.392l170.9056-89.856a66.56 66.56 0 0 1 62.1568 0l170.9568 89.856a66.56 66.56 0 0 0 89.9584-27.392l-25.6-149.8624a66.56 66.56 0 0 1 6.9632-42.6496l-6.9632-40.96a66.56 66.56 0 0 1 18.7904-59.0848l138.24-134.8096a74.6496 74.6496 0 0 0 5.6832-6.0928z" fill="currentColor"/>
<path d="M798.3104 777.5744l-18.5856-108.544a66.56 66.56 0 0 1 18.9952-59.0848l86.0672-83.9168-175.9232-25.6a66.56 66.56 0 0 1-50.2784-36.5056L573.44 290.7648a66.56 66.56 0 0 0-119.808 0L368.0768 463.9232a66.56 66.56 0 0 1-50.2784 36.5056l-175.9232 25.6 86.0672 83.9168a66.56 66.56 0 0 1 19.2512 59.0848l-18.6368 108.544a66.816 66.816 0 0 1 18.6368 58.4704l-14.08 81.92a66.56 66.56 0 0 0 78.336 11.9296l170.9056-89.856a66.56 66.56 0 0 1 62.1568 0l170.9568 89.856a66.56 66.56 0 0 0 78.1312-12.032l-14.0288-81.92a66.56 66.56 0 0 1 18.7392-58.368z" fill="currentColor"/>
<path d="M798.72 609.9456l11.5712-11.264-101.4272-14.7456a66.56 66.56 0 0 1-50.2784-36.5568L573.44 374.2208a66.816 66.816 0 0 0-119.808 0l-85.5552 173.1584a66.56 66.56 0 0 1-50.2784 36.5568l-101.376 14.7456 11.52 11.264a66.56 66.56 0 0 1 19.2512 59.0848l-30.72 180.0192 11.6224 11.3664a66.8672 66.8672 0 0 1 19.2512 59.136l-1.5872 8.2432a65.8432 65.8432 0 0 0 65.6896 1.9968l170.9056-89.856a66.56 66.56 0 0 1 62.1568 0l170.9568 89.856a65.7408 65.7408 0 0 0 65.6384-1.9968l-1.3824-8.2432a66.56 66.56 0 0 1 18.9952-59.136l11.6736-11.3664-30.72-180.0192a66.56 66.56 0 0 1 19.0464-59.0848z" fill="currentColor"/>
<path d="M311.4496 929.792l170.9056-89.856a66.56 66.56 0 0 1 62.1568 0l170.9568 89.856a66.56 66.56 0 0 0 96.8704-70.4l-31.1296-181.4528-72.1408-10.24a66.816 66.816 0 0 1-50.2784-36.5568L573.44 457.728a66.816 66.816 0 0 0-119.808 0l-85.5552 173.1584a66.816 66.816 0 0 1-50.2784 36.5568l-72.1408 10.24-31.1296 181.7088a66.56 66.56 0 0 0 96.9216 70.4z" fill="currentColor"/>
<path d="M513.4336 694.784A166.2464 166.2464 0 0 1 356.6592 583.68a40.96 40.96 0 1 1 77.312-27.0848 84.224 84.224 0 0 0 158.1568 2.1504 40.96 40.96 0 0 1 76.544 29.184 166.9632 166.9632 0 0 1-155.2384 106.8544z" fill="#FFFFFF"/>
</svg>
</span>
<span class="nav-label">首页</span>
</button>
<!-- 源码(齿轮图标) -->
<button class="nav-item" data-target="page-source">
<span class="nav-icon">
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M508.3136 512.9728l312.32-269.056a412.2112 412.2112 0 1 0 26.4704 504.064z" fill="currentColor"/>
<path d="M700.1088 504.8832m-62.8224 0a62.8224 62.8224 0 1 0 125.6448 0 62.8224 62.8224 0 1 0-125.6448 0Z" fill="currentColor"/>
<path d="M861.4912 504.8832m-62.8224 0a62.8224 62.8224 0 1 0 125.6448 0 62.8224 62.8224 0 1 0-125.6448 0Z" fill="currentColor"/>
<path d="M525.5168 201.1648C329.728 201.1648 162.7136 317.44 97.28 480.4096c-0.8192 10.752-1.3824 21.6064-1.3824 32.5632a412.2112 412.2112 0 0 0 750.8992 235.008l-338.688-235.008L783.36 276.1216a474.8288 474.8288 0 0 0-257.8432-74.9568z" fill="currentColor"/>
<path d="M922.1632 521.0624a435.2 435.2 0 0 0-61.696-79.0016 62.8224 62.8224 0 1 0 61.696 79.0016zM525.5168 304.3328c-192.6144 0-357.2736 112.3328-424.704 271.36a412.2624 412.2624 0 0 0 746.1888 172.3904l-338.688-235.008 200.2944-172.6976a479.0272 479.0272 0 0 0-183.0912-36.0448z" fill="currentColor"/>
<path d="M799.744 493.6192a62.6176 62.6176 0 0 0 79.3088 71.68 449.3312 449.3312 0 0 0-79.3088-71.68zM525.5168 407.4496c-178.2272 0-332.544 96.256-408.0128 236.544a412.16 412.16 0 0 0 729.4976 103.9872l-338.688-235.008 111.7184-96.256a486.4 486.4 0 0 0-94.5152-9.2672z" fill="currentColor"/>
<path d="M640.3584 524.3392a62.72 62.72 0 0 0 93.2864 33.7408 469.0944 469.0944 0 0 0-93.2864-33.7408zM510.6688 510.976c-153.6 4.608-287.9488 80.5376-367.2064 193.8944a412.2112 412.2112 0 0 0 703.5392 43.1104l-338.688-235.008z" fill="currentColor"/>
<path d="M531.0976 287.7952m-55.9104 0a55.9104 55.9104 0 1 0 111.8208 0 55.9104 55.9104 0 1 0-111.8208 0Z" fill="#FFFFFF"/>
</svg>
</span>
<span class="nav-label">源码</span>
</button>
</nav>
<script>
(function() {
const navItems = document.querySelectorAll('.nav-item');
const pages = {
home: document.getElementById('page-home'),
source: document.getElementById('page-source')
};
function switchPage(targetId) {
Object.values(pages).forEach(p => p.classList.remove('active'));
const target = document.getElementById(targetId);
if (target) target.classList.add('active');
navItems.forEach(item => {
item.classList.toggle('active', item.dataset.target === targetId);
});
}
navItems.forEach(item => {
item.addEventListener('click', function(e) {
const target = this.dataset.target;
if (target) switchPage(target);
});
});
// 如果URL带有file参数,切换到源码页
const urlParams = new URLSearchParams(window.location.search);
const fileParam = urlParams.get('file');
if (fileParam) {
switchPage('page-source');
const items = document.querySelectorAll('.source-file-list .file-item');
items.forEach(item => {
item.classList.toggle('active', item.dataset.file === fileParam);
});
}
})();
</script>
</body>
</html>
<?php