增加配置文件

This commit is contained in:
2026-06-02 13:52:47 +08:00
parent 6117222625
commit aab3aeb5b2
31 changed files with 3326 additions and 198 deletions
+372
View File
@@ -92,6 +92,12 @@ function showPage(pageName) {
case 'comments':
loadComments();
break;
case 'themes':
loadThemes();
break;
case 'theme-editor':
// 主题编辑器由 editTheme() 函数加载
break;
}
}
@@ -614,3 +620,369 @@ function getStatusText(status) {
};
return map[status] || status;
}
// ==================== 主题管理 ====================
// 加载主题列表
let currentTheme = null;
async function loadThemes() {
try {
// 获取当前主题
const currentRes = await fetch(`${API_BASE}/theme`, {
headers: getHeaders()
});
const currentData = await currentRes.json();
currentTheme = currentData.theme;
// 获取所有可用主题
const themesRes = await fetch(`${API_BASE}/themes`, {
headers: getHeaders()
});
const themesData = await themesRes.json();
// 填充下拉列表
const themeSelect = document.getElementById('theme-select');
themeSelect.innerHTML = '';
themesData.themes.forEach(theme => {
const option = document.createElement('option');
option.value = theme;
option.textContent = theme;
if (theme === currentTheme) {
option.selected = true;
}
themeSelect.appendChild(option);
});
// 显示主题列表
displayThemeList(themesData.themes, currentTheme);
} catch (error) {
console.error('加载主题失败:', error);
showThemeMessage('加载主题失败', 'error');
}
}
// 显示主题列表
function displayThemeList(themes, currentTheme) {
const themeList = document.getElementById('theme-list');
themeList.innerHTML = '';
themes.forEach(theme => {
const themeCard = document.createElement('div');
themeCard.className = `theme-card ${theme === currentTheme ? 'active' : ''}`;
themeCard.innerHTML = `
<div class="theme-card-header">
<h3>${theme}</h3>
${theme === currentTheme ? '<span class="theme-badge">当前使用</span>' : ''}
</div>
<div class="theme-card-body">
<p>主题名称: ${theme}</p>
<p>状态: ${theme === currentTheme ? '使用中' : '未使用'}</p>
</div>
<div class="theme-card-actions">
<button class="btn-small btn-secondary" onclick="editTheme('${theme}')">编辑</button>
${theme !== currentTheme ? `<button class="btn-small btn-primary" onclick="quickSwitch('${theme}')">切换</button>` : ''}
</div>
`;
themeList.appendChild(themeCard);
});
}
// 切换主题
async function switchTheme() {
const themeSelect = document.getElementById('theme-select');
const selectedTheme = themeSelect.value;
if (!selectedTheme) {
showThemeMessage('请选择一个主题', 'error');
return;
}
if (selectedTheme === currentTheme) {
showThemeMessage('当前已经是该主题', 'warning');
return;
}
try {
const response = await fetch(`${API_BASE}/theme`, {
method: 'POST',
headers: {
...getHeaders(),
'Content-Type': 'application/json'
},
body: JSON.stringify({ theme: selectedTheme })
});
const data = await response.json();
if (response.ok) {
showThemeMessage(data.message || '主题切换成功', 'success');
currentTheme = selectedTheme;
// 刷新主题列表显示
loadThemes();
} else {
showThemeMessage(data.error || '主题切换失败', 'error');
}
} catch (error) {
console.error('切换主题失败:', error);
showThemeMessage('切换主题失败', 'error');
}
}
// 显示主题消息
function showThemeMessage(message, type = 'info') {
const messageEl = document.getElementById('theme-message');
messageEl.textContent = message;
messageEl.className = `theme-message ${type}`;
messageEl.style.display = 'block';
// 3秒后自动隐藏
setTimeout(() => {
messageEl.style.display = 'none';
}, 3000);
}
// 显示创建主题弹窗
function showCreateThemeModal() {
document.getElementById('theme-modal').classList.remove('hidden');
document.getElementById('new-theme-name').value = '';
document.getElementById('theme-template').value = 'default';
document.getElementById('create-css').checked = true;
}
// 隐藏创建主题弹窗
function hideThemeModal() {
document.getElementById('theme-modal').classList.add('hidden');
}
// 创建主题表单提交
document.addEventListener('DOMContentLoaded', () => {
const createThemeForm = document.getElementById('create-theme-form');
if (createThemeForm) {
createThemeForm.addEventListener('submit', handleCreateTheme);
}
});
async function handleCreateTheme(e) {
e.preventDefault();
const themeName = document.getElementById('new-theme-name').value.trim();
const template = document.getElementById('theme-template').value;
const createCSS = document.getElementById('create-css').checked;
if (!themeName) {
showThemeMessage('请输入主题名称', 'error');
return;
}
try {
const response = await fetch(`${API_BASE}/themes/create`, {
method: 'POST',
headers: {
...getHeaders(),
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: themeName,
template: template,
create_css: createCSS
})
});
const data = await response.json();
if (response.ok) {
showThemeMessage(data.message || '主题创建成功', 'success');
hideThemeModal();
// 刷新主题列表
setTimeout(() => {
loadThemes();
}, 500);
} else {
showThemeMessage(data.error || '主题创建失败', 'error');
}
} catch (error) {
console.error('创建主题失败:', error);
showThemeMessage('创建主题失败', 'error');
}
}
// 快速切换主题
async function quickSwitch(theme) {
try {
const response = await fetch(`${API_BASE}/theme`, {
method: 'POST',
headers: {
...getHeaders(),
'Content-Type': 'application/json'
},
body: JSON.stringify({ theme: theme })
});
const data = await response.json();
if (response.ok) {
showThemeMessage(data.message || '主题切换成功', 'success');
currentTheme = theme;
loadThemes();
} else {
showThemeMessage(data.error || '主题切换失败', 'error');
}
} catch (error) {
console.error('切换主题失败:', error);
showThemeMessage('切换主题失败', 'error');
}
}
// ==================== 主题编辑器 ====================
let currentEditingTheme = null;
let currentEditingFile = null;
let themeFiles = [];
// 编辑主题
async function editTheme(themeName) {
currentEditingTheme = themeName;
currentEditingFile = null;
document.getElementById('editor-theme-name').textContent = themeName;
document.getElementById('current-file-name').textContent = '选择文件进行编辑';
document.getElementById('theme-file-editor').value = '';
showPage('theme-editor');
// 加载主题文件列表
await loadThemeFiles(themeName);
}
// 加载主题文件列表
async function loadThemeFiles(themeName) {
try {
const response = await fetch(`${API_BASE}/themes/${themeName}/files`, {
headers: getHeaders()
});
const data = await response.json();
if (response.ok) {
themeFiles = data.files || [];
displayThemeFiles(themeFiles);
} else {
showThemeMessage(data.error || '加载文件列表失败', 'error');
}
} catch (error) {
console.error('加载文件列表失败:', error);
showThemeMessage('加载文件列表失败', 'error');
}
}
// 显示主题文件列表
function displayThemeFiles(files) {
const filesContainer = document.getElementById('theme-files');
filesContainer.innerHTML = '';
if (files.length === 0) {
filesContainer.innerHTML = '<p class="no-files">暂无文件</p>';
return;
}
files.forEach(file => {
const fileItem = document.createElement('div');
fileItem.className = 'theme-file-item';
fileItem.innerHTML = `
<span class="file-icon">${getFileIcon(file)}</span>
<span class="file-name">${file}</span>
`;
fileItem.onclick = () => loadFileContent(file);
filesContainer.appendChild(fileItem);
});
}
// 获取文件图标
function getFileIcon(filename) {
if (filename.endsWith('.html')) return '📄';
if (filename.endsWith('.css')) return '🎨';
if (filename.endsWith('.js')) return '📜';
return '📁';
}
// 加载文件内容
async function loadFileContent(filename) {
try {
currentEditingFile = filename;
const response = await fetch(`${API_BASE}/themes/${currentEditingTheme}/files/${filename}`, {
headers: getHeaders()
});
const data = await response.json();
if (response.ok) {
document.getElementById('current-file-name').textContent = filename;
document.getElementById('theme-file-editor').value = data.content || '';
// 高亮当前文件
document.querySelectorAll('.theme-file-item').forEach(item => {
item.classList.remove('active');
});
event.currentTarget.classList.add('active');
} else {
showThemeMessage(data.error || '加载文件失败', 'error');
}
} catch (error) {
console.error('加载文件失败:', error);
showThemeMessage('加载文件失败', 'error');
}
}
// 保存当前文件
async function saveCurrentFile() {
if (!currentEditingTheme || !currentEditingFile) {
showThemeMessage('请先选择文件', 'warning');
return;
}
const content = document.getElementById('theme-file-editor').value;
try {
const response = await fetch(`${API_BASE}/themes/${currentEditingTheme}/files/${currentEditingFile}`, {
method: 'PUT',
headers: {
...getHeaders(),
'Content-Type': 'application/json'
},
body: JSON.stringify({ content: content })
});
const data = await response.json();
if (response.ok) {
showThemeMessage(data.message || '文件保存成功', 'success');
// 如果是模板文件,重新加载主题
if (currentEditingFile.endsWith('.html')) {
const renderer = await fetch(`${API_BASE}/theme`, { headers: getHeaders() });
const rendererData = await renderer.json();
if (rendererData.theme === currentEditingTheme) {
// 重新加载当前主题以应用更改
await fetch(`${API_BASE}/theme`, {
method: 'POST',
headers: {
...getHeaders(),
'Content-Type': 'application/json'
},
body: JSON.stringify({ theme: currentEditingTheme })
});
}
}
} else {
showThemeMessage(data.error || '保存文件失败', 'error');
}
} catch (error) {
console.error('保存文件失败:', error);
showThemeMessage('保存文件失败', 'error');
}
}
+79 -1
View File
@@ -4,6 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台管理 - GoBlog</title>
<link rel="icon" href="/static/images/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="/static/admin/style.css">
</head>
<body>
@@ -20,6 +21,7 @@
<a href="#tags" class="menu-item" data-page="tags">标签管理</a>
<a href="#pages" class="menu-item" data-page="pages">页面管理</a>
<a href="#comments" class="menu-item" data-page="comments">评论管理</a>
<a href="#themes" class="menu-item" data-page="themes">主题管理</a>
</nav>
<div class="user-info">
<span id="username">Admin</span>
@@ -218,6 +220,50 @@
<tbody id="comments-list"></tbody>
</table>
</div>
<!-- 主题管理 -->
<div id="themes-page" class="page hidden">
<div class="page-header">
<h1>主题管理</h1>
<button class="btn-primary" onclick="showCreateThemeModal()">新建主题</button>
</div>
<div class="theme-settings">
<div class="form-group">
<label>当前主题</label>
<select id="theme-select" class="theme-selector">
<option value="">加载中...</option>
</select>
</div>
<button class="btn-primary" onclick="switchTheme()">切换主题</button>
<div id="theme-message" class="theme-message"></div>
</div>
<div class="theme-list" id="theme-list">
<!-- 主题列表将动态加载 -->
</div>
</div>
<!-- 主题编辑器 -->
<div id="theme-editor-page" class="page hidden">
<div class="page-header">
<h1>编辑主题: <span id="editor-theme-name"></span></h1>
<div>
<button class="btn-secondary" onclick="showPage('themes')">返回</button>
<button class="btn-primary" onclick="saveCurrentFile()">保存文件</button>
</div>
</div>
<div class="theme-editor-container">
<div class="theme-file-list">
<h3>文件列表</h3>
<div id="theme-files"></div>
</div>
<div class="theme-editor-content">
<div class="editor-header">
<h3 id="current-file-name">选择文件进行编辑</h3>
</div>
<textarea id="theme-file-editor" class="code-editor" placeholder="选择左侧文件进行编辑..."></textarea>
</div>
</div>
</div>
</main>
</div>
@@ -247,6 +293,38 @@
</div>
</div>
<script src="/static/admin/app.js?v=6"></script>
<!-- 创建主题弹窗 -->
<div id="theme-modal" class="modal hidden">
<div class="modal-content modal-large">
<h3>新建主题</h3>
<form id="create-theme-form">
<div class="form-group">
<label>主题名称 *</label>
<input type="text" id="new-theme-name" required placeholder="例如: mytheme">
<small>只能包含字母、数字和下划线</small>
</div>
<div class="form-group">
<label>基于模板创建</label>
<select id="theme-template">
<option value="default">default(默认主题)</option>
<option value="minimal">minimal(极简主题)</option>
<option value="blank">blank(空白主题)</option>
</select>
<small>选择新主题的初始模板</small>
</div>
<div class="form-group">
<label>
<input type="checkbox" id="create-css" checked> 创建样式文件
</label>
</div>
<div class="modal-actions">
<button type="button" class="btn-secondary" onclick="hideThemeModal()">取消</button>
<button type="submit" class="btn-primary">创建主题</button>
</div>
</form>
</div>
</div>
<script src="/static/admin/app.js?v=9"></script>
</body>
</html>
+304
View File
@@ -358,3 +358,307 @@ body {
grid-template-columns: 1fr;
}
}
/* 主题管理 */
.theme-settings {
background: #fff;
padding: 24px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
margin-bottom: 24px;
}
.theme-settings .form-group {
margin-bottom: 20px;
}
.theme-settings label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #333;
}
.theme-selector {
width: 100%;
max-width: 400px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
background: #fff;
cursor: pointer;
}
.theme-selector:focus {
outline: none;
border-color: #1890ff;
}
.theme-settings .btn-primary {
margin-top: 10px;
}
.theme-message {
margin-top: 15px;
padding: 10px 15px;
border-radius: 4px;
display: none;
}
.theme-message.success {
background: #f6ffed;
border: 1px solid #b7eb8f;
color: #52c41a;
}
.theme-message.error {
background: #fff2f0;
border: 1px solid #ffccc7;
color: #ff4d4f;
}
.theme-message.warning {
background: #fffbe6;
border: 1px solid #ffe58f;
color: #faad14;
}
.theme-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.theme-card {
background: #fff;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
border: 2px solid transparent;
transition: all 0.3s;
}
.theme-card:hover {
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
transform: translateY(-2px);
}
.theme-card.active {
border-color: #1890ff;
background: #f0f9ff;
}
.theme-card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
padding-bottom: 15px;
border-bottom: 1px solid #eee;
}
.theme-card-header h3 {
font-size: 18px;
color: #333;
margin: 0;
}
.theme-badge {
background: #1890ff;
color: #fff;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
}
.theme-card-body p {
margin: 8px 0;
color: #666;
font-size: 14px;
}
@media (max-width: 768px) {
.theme-list {
grid-template-columns: 1fr;
}
.theme-settings {
padding: 16px;
}
.theme-selector {
max-width: 100%;
}
}
/* 大尺寸模态框 */
.modal-large {
max-width: 600px;
}
.modal-large .form-group small {
display: block;
margin-top: 5px;
color: #999;
font-size: 12px;
}
.modal-large input[type="text"] {
width: 100%;
}
.modal-large input[type="checkbox"] {
margin-right: 8px;
}
/* 主题卡片操作按钮 */
.theme-card-actions {
display: flex;
gap: 10px;
margin-top: 15px;
padding-top: 15px;
border-top: 1px solid #eee;
}
.btn-small {
padding: 6px 12px;
font-size: 13px;
border: none;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s;
}
.btn-small.btn-secondary {
background: #f5f5f5;
color: #666;
}
.btn-small.btn-secondary:hover {
background: #e8e8e8;
}
.btn-small.btn-primary {
background: #1890ff;
color: #fff;
}
.btn-small.btn-primary:hover {
background: #40a9ff;
}
/* 主题编辑器 */
.theme-editor-container {
display: grid;
grid-template-columns: 280px 1fr;
gap: 20px;
height: calc(100vh - 200px);
}
.theme-file-list {
background: #fff;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
overflow-y: auto;
}
.theme-file-list h3 {
margin: 0 0 15px;
font-size: 16px;
color: #333;
}
.theme-file-item {
padding: 12px;
margin-bottom: 8px;
background: #f9f9f9;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s;
display: flex;
align-items: center;
gap: 10px;
}
.theme-file-item:hover {
background: #e6f7ff;
}
.theme-file-item.active {
background: #1890ff;
color: #fff;
}
.theme-file-item .file-icon {
font-size: 18px;
}
.theme-file-item .file-name {
flex: 1;
font-size: 14px;
}
.theme-editor-content {
background: #fff;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
display: flex;
flex-direction: column;
}
.editor-header {
margin-bottom: 15px;
padding-bottom: 15px;
border-bottom: 1px solid #eee;
}
.editor-header h3 {
margin: 0;
font-size: 16px;
color: #333;
}
.code-editor {
flex: 1;
width: 100%;
padding: 15px;
border: 1px solid #ddd;
border-radius: 6px;
font-family: 'Courier New', monospace;
font-size: 14px;
line-height: 1.6;
resize: none;
background: #f9f9f9;
color: #333;
}
.code-editor:focus {
outline: none;
border-color: #1890ff;
background: #fff;
}
.no-files {
text-align: center;
color: #999;
padding: 40px 20px;
}
@media (max-width: 1024px) {
.theme-editor-container {
grid-template-columns: 1fr;
height: auto;
}
.theme-file-list {
max-height: 300px;
}
.code-editor {
min-height: 500px;
}
}
+542
View File
@@ -0,0 +1,542 @@
/* 极简主题 - Minimal Theme */
/* 基础样式重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Georgia', 'Times New Roman', serif;
font-size: 16px;
line-height: 1.8;
color: #e0e0e0;
background-color: #121212;
}
a {
color: #64b5f6;
text-decoration: none;
transition: color 0.3s ease;
}
a:hover {
color: #90caf9;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 0 25px;
}
.wrapper {
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* 头部样式 */
.header {
background: #1e1e1e;
padding: 40px 0;
border-bottom: 1px solid #333;
margin-bottom: 40px;
}
.site-title {
font-size: 32px;
font-weight: 400;
letter-spacing: 1px;
}
.site-title a {
color: #e0e0e0;
}
.site-title a:hover {
color: #64b5f6;
}
.site-desc {
color: #9e9e9e;
margin-top: 10px;
font-style: italic;
}
.main-nav {
margin-top: 25px;
padding-top: 25px;
border-top: 1px solid #333;
}
.main-nav a {
margin-right: 25px;
color: #9e9e9e;
font-size: 15px;
font-weight: 300;
}
.main-nav a:hover {
color: #64b5f6;
}
/* 主内容区 */
.main {
flex: 1;
}
/* 文章列表 */
.post-list {
display: flex;
flex-direction: column;
gap: 40px;
}
.post-item {
padding-bottom: 40px;
border-bottom: 1px solid #333;
}
.post-item:last-child {
border-bottom: none;
}
.post-title {
font-size: 26px;
margin-bottom: 15px;
font-weight: 400;
}
.post-title a {
color: #e0e0e0;
}
.post-title a:hover {
color: #64b5f6;
}
.top-badge {
display: inline-block;
background: #d32f2f;
color: #fff;
font-size: 11px;
padding: 3px 10px;
border-radius: 3px;
margin-left: 10px;
vertical-align: middle;
font-weight: 400;
}
.post-meta {
color: #757575;
font-size: 14px;
margin-bottom: 20px;
font-style: italic;
}
.post-meta span {
margin-right: 20px;
}
.post-meta a {
color: #9e9e9e;
}
.tag {
display: inline-block;
background: #2c2c2c;
padding: 3px 10px;
border-radius: 3px;
font-size: 12px;
margin-right: 8px;
color: #9e9e9e;
}
.tag:hover {
background: #383838;
color: #64b5f6;
}
.post-summary {
color: #b0b0b0;
line-height: 1.9;
margin-bottom: 20px;
}
.read-more {
display: inline-block;
color: #64b5f6;
font-weight: 400;
border-bottom: 1px solid transparent;
padding-bottom: 2px;
}
.read-more:hover {
border-bottom-color: #64b5f6;
}
/* 文章详情 */
.post-detail {
background: #1e1e1e;
padding: 45px;
border-radius: 4px;
border: 1px solid #333;
}
.post-header {
margin-bottom: 35px;
padding-bottom: 25px;
border-bottom: 1px solid #333;
}
.post-detail .post-title {
font-size: 32px;
margin-bottom: 20px;
font-weight: 400;
line-height: 1.4;
}
.post-body {
line-height: 1.9;
color: #d0d0d0;
}
.post-body h2,
.post-body h3,
.post-body h4 {
margin: 35px 0 20px;
color: #e0e0e0;
font-weight: 400;
}
.post-body h2 {
font-size: 26px;
border-bottom: 1px solid #333;
padding-bottom: 10px;
}
.post-body h3 {
font-size: 22px;
}
.post-body p {
margin-bottom: 20px;
}
.post-body img {
max-width: 100%;
border-radius: 4px;
border: 1px solid #333;
}
.post-body pre {
background: #252525;
padding: 20px;
border-radius: 4px;
overflow-x: auto;
border: 1px solid #333;
margin: 25px 0;
}
.post-body code {
background: #252525;
padding: 3px 8px;
border-radius: 3px;
font-family: 'Courier New', monospace;
font-size: 14px;
border: 1px solid #333;
}
.post-body blockquote {
border-left: 3px solid #64b5f6;
padding-left: 20px;
margin: 25px 0;
color: #9e9e9e;
font-style: italic;
}
.post-body ul,
.post-body ol {
margin: 20px 0;
padding-left: 30px;
}
.post-body li {
margin-bottom: 10px;
}
/* 页面 */
.page-detail {
background: #1e1e1e;
padding: 45px;
border-radius: 4px;
border: 1px solid #333;
}
.page-title {
font-size: 32px;
margin-bottom: 25px;
font-weight: 400;
}
.page-body {
line-height: 1.9;
color: #d0d0d0;
}
/* 分页 */
.pagination {
display: flex;
justify-content: center;
align-items: center;
gap: 25px;
margin-top: 50px;
padding: 25px;
}
.pagination a {
padding: 10px 20px;
background: #1e1e1e;
border: 1px solid #333;
border-radius: 4px;
color: #9e9e9e;
transition: all 0.3s ease;
}
.pagination a:hover {
background: #2c2c2c;
border-color: #64b5f6;
color: #64b5f6;
}
.page-info {
color: #757575;
}
/* 评论区 */
.comments-section {
background: #1e1e1e;
padding: 35px;
margin-top: 40px;
border-radius: 4px;
border: 1px solid #333;
}
.comments-section h3 {
margin-bottom: 25px;
font-weight: 400;
font-size: 22px;
color: #e0e0e0;
}
.comment-form {
margin-bottom: 35px;
padding-bottom: 35px;
border-bottom: 1px solid #333;
}
.form-group {
margin-bottom: 20px;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 12px;
background: #252525;
border: 1px solid #333;
border-radius: 4px;
font-size: 14px;
color: #e0e0e0;
font-family: inherit;
}
.form-group input:focus,
.form-group textarea:focus {
outline: none;
border-color: #64b5f6;
}
.form-group textarea {
min-height: 120px;
resize: vertical;
}
.comment-form button {
background: #64b5f6;
color: #121212;
border: none;
padding: 12px 30px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: background 0.3s ease;
}
.comment-form button:hover {
background: #90caf9;
}
.comments-list {
display: flex;
flex-direction: column;
gap: 25px;
}
.comment-item {
padding: 20px;
background: #252525;
border-radius: 4px;
border: 1px solid #333;
}
.comment-item.child {
margin-left: 35px;
margin-top: 15px;
background: #2a2a2a;
}
.comment-header {
margin-bottom: 12px;
font-size: 14px;
}
.comment-author {
font-weight: 500;
color: #e0e0e0;
}
.comment-author a {
color: #64b5f6;
}
.comment-date {
color: #757575;
margin-left: 12px;
}
.comment-content {
color: #b0b0b0;
line-height: 1.7;
}
.no-comments {
color: #757575;
text-align: center;
padding: 40px;
}
/* 空状态 */
.empty {
text-align: center;
padding: 80px;
color: #757575;
background: #1e1e1e;
border-radius: 4px;
border: 1px solid #333;
}
/* 底部 */
.footer {
background: #1e1e1e;
padding: 35px 0;
margin-top: 60px;
text-align: center;
color: #757575;
border-top: 1px solid #333;
}
/* 文章导航 - 上一篇/下一篇 */
.post-navigation {
display: flex;
justify-content: space-between;
gap: 25px;
margin: 35px 0;
padding: 25px;
background: #1e1e1e;
border-radius: 4px;
border: 1px solid #333;
}
.nav-prev,
.nav-next {
flex: 1;
}
.nav-next {
text-align: right;
}
.nav-link {
display: flex;
flex-direction: column;
padding: 15px;
border-radius: 4px;
transition: background-color 0.3s;
}
.nav-link:hover {
background-color: #252525;
}
.nav-link.disabled {
color: #757575;
cursor: not-allowed;
}
.nav-link.disabled:hover {
background-color: transparent;
}
.nav-label {
font-size: 13px;
color: #757575;
margin-bottom: 8px;
}
.nav-title {
font-size: 15px;
font-weight: 400;
color: #e0e0e0;
line-height: 1.5;
}
.nav-link:hover .nav-title {
color: #64b5f6;
}
/* 响应式 */
@media (max-width: 768px) {
.site-title {
font-size: 26px;
}
.post-detail,
.page-detail {
padding: 25px;
}
.post-detail .post-title {
font-size: 24px;
}
.post-meta span {
display: block;
margin: 8px 0;
}
.post-navigation {
flex-direction: column;
gap: 20px;
}
.nav-next {
text-align: left;
}
.comment-item.child {
margin-left: 20px;
}
}
+56
View File
@@ -0,0 +1,56 @@
/* mytheme Theme */
/* 在此添加你的样式 */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
margin: 0;
padding: 0;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
.header {
background: #fff;
padding: 20px 0;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.site-title {
margin: 0;
}
.site-title a {
color: #333;
text-decoration: none;
}
.site-desc {
color: #666;
margin: 10px 0 0;
}
.main-nav {
margin-top: 15px;
}
.main-nav a {
margin-right: 15px;
color: #666;
text-decoration: none;
}
.main {
padding: 30px 0;
min-height: 500px;
}
.footer {
background: #f5f5f5;
padding: 20px 0;
text-align: center;
color: #999;
}
+207 -1
View File
@@ -23,11 +23,208 @@ a:hover {
}
.container {
max-width: 900px;
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* 内容区域布局 */
.content-wrapper {
display: flex;
gap: 30px;
align-items: flex-start;
}
.main-content {
flex: 1;
min-width: 0;
}
/* 侧边栏 */
.sidebar {
width: 300px;
flex-shrink: 0;
display: flex;
flex-direction: column;
gap: 20px;
}
.sidebar-widget {
background: #fff;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
.widget-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 2px solid #1890ff;
color: #333;
}
/* 博客信息 */
.blog-info {
text-align: center;
}
.blog-avatar {
width: 80px;
height: 80px;
border-radius: 50%;
margin-bottom: 10px;
}
.blog-name {
font-size: 16px;
font-weight: 600;
color: #333;
margin-bottom: 8px;
}
.blog-description {
font-size: 14px;
color: #666;
line-height: 1.6;
}
.blog-stats {
display: flex;
justify-content: space-around;
margin-top: 15px;
padding-top: 15px;
border-top: 1px solid #eee;
}
.stat-item {
text-align: center;
}
.stat-number {
font-size: 20px;
font-weight: 600;
color: #1890ff;
}
.stat-label {
font-size: 12px;
color: #999;
margin-top: 4px;
}
/* 搜索框 */
.search-form {
display: flex;
gap: 8px;
}
.search-input {
flex: 1;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
outline: none;
transition: border-color 0.2s;
}
.search-input:focus {
border-color: #1890ff;
}
.search-btn {
padding: 8px 16px;
background: #1890ff;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: background 0.2s;
}
.search-btn:hover {
background: #40a9ff;
}
/* 分类列表 */
.category-list {
list-style: none;
}
.category-item {
margin-bottom: 8px;
}
.category-link {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
color: #666;
border-radius: 4px;
transition: all 0.2s;
}
.category-link:hover {
background: #f0f9ff;
color: #1890ff;
}
.category-count {
background: #f0f0f0;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
color: #999;
}
/* 标签云 */
.tag-cloud {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.tag-item {
display: inline-block;
padding: 4px 12px;
background: #f0f0f0;
color: #666;
border-radius: 4px;
font-size: 13px;
transition: all 0.2s;
}
.tag-item:hover {
background: #1890ff;
color: #fff;
}
/* 系统菜单 */
.system-menu {
list-style: none;
}
.system-menu-item {
margin-bottom: 8px;
}
.system-menu-link {
display: block;
padding: 8px 12px;
color: #666;
border-radius: 4px;
transition: all 0.2s;
}
.system-menu-link:hover {
background: #f0f9ff;
color: #1890ff;
}
/* 头部样式 */
.header {
background: #fff;
@@ -441,4 +638,13 @@ a:hover {
.nav-next {
text-align: left;
}
/* 移动端 sidebar 隐藏或置底 */
.content-wrapper {
flex-direction: column;
}
.sidebar {
width: 100%;
}
}