248 lines
8.9 KiB
HTML
248 lines
8.9 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Dashboard - Blog</title>
|
|
<link rel="stylesheet" href="/static/css/material.css">
|
|
</head>
|
|
<body>
|
|
<header class="header">
|
|
<div class="header__content">
|
|
<a href="/" class="header__logo">📝 Blog</a>
|
|
<nav class="header__nav">
|
|
<a href="/">Home</a>
|
|
<a href="#about">About</a>
|
|
<a href="/feed">RSS Feed</a>
|
|
<span style="padding: 8px 16px; background: rgba(255,255,255,0.2); border-radius: 20px;">Dashboard</span>
|
|
</nav>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="container" style="padding: 40px 16px;">
|
|
<div style="display: grid; grid-template-columns: 1fr 2fr; gap: 40px; align-items: start;">
|
|
<!-- Sidebar Navigation -->
|
|
<aside style="position: sticky; top: 20px;">
|
|
<div class="card">
|
|
<h3 style="margin-top: 0;">Dashboard</h3>
|
|
<nav style="display: flex; flex-direction: column; gap: 8px;">
|
|
<button class="sidebar-btn active" data-view="editor" style="
|
|
text-align: left;
|
|
background: none;
|
|
border: none;
|
|
padding: 12px;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
color: var(--md-sys-color-primary);
|
|
font-weight: 500;
|
|
">
|
|
✍️ Write Post
|
|
</button>
|
|
<button class="sidebar-btn" data-view="posts" style="
|
|
text-align: left;
|
|
background: none;
|
|
border: none;
|
|
padding: 12px;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
color: var(--md-sys-color-on-background);
|
|
">
|
|
📚 My Posts
|
|
</button>
|
|
<button class="sidebar-btn" data-view="stats" style="
|
|
text-align: left;
|
|
background: none;
|
|
border: none;
|
|
padding: 12px;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
color: var(--md-sys-color-on-background);
|
|
">
|
|
📊 Statistics
|
|
</button>
|
|
<hr style="border: none; border-top: 1px solid var(--md-sys-color-outline-variant); margin: 12px 0;">
|
|
<button onclick="handleLogout()" style="
|
|
text-align: left;
|
|
background: none;
|
|
border: none;
|
|
padding: 12px;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
color: var(--md-sys-color-error);
|
|
">
|
|
🚪 Logout
|
|
</button>
|
|
</nav>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- Main Content -->
|
|
<section>
|
|
<!-- Editor View -->
|
|
<div id="editor-view" class="view-section" style="display: block;">
|
|
<div id="post-editor"></div>
|
|
</div>
|
|
|
|
<!-- Posts View -->
|
|
<div id="posts-view" class="view-section" style="display: none;">
|
|
<h2>My Posts</h2>
|
|
<div id="user-posts-list" style="margin-top: 24px;">
|
|
Loading your posts...
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Statistics View -->
|
|
<div id="stats-view" class="view-section" style="display: none;">
|
|
<h2>Statistics</h2>
|
|
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-top: 24px;">
|
|
<div class="card">
|
|
<div style="font-size: 12px; color: var(--md-sys-color-on-surface-variant); text-transform: uppercase; letter-spacing: 0.5px;">Total Posts</div>
|
|
<div id="stat-total-posts" style="font-size: 32px; font-weight: 600; margin-top: 8px;">0</div>
|
|
</div>
|
|
<div class="card">
|
|
<div style="font-size: 12px; color: var(--md-sys-color-on-surface-variant); text-transform: uppercase; letter-spacing: 0.5px;">Published</div>
|
|
<div id="stat-published-posts" style="font-size: 32px; font-weight: 600; margin-top: 8px;">0</div>
|
|
</div>
|
|
<div class="card">
|
|
<div style="font-size: 12px; color: var(--md-sys-color-on-surface-variant); text-transform: uppercase; letter-spacing: 0.5px;">Drafts</div>
|
|
<div id="stat-draft-posts" style="font-size: 32px; font-weight: 600; margin-top: 8px;">0</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</main>
|
|
|
|
<footer class="footer">
|
|
<div class="footer__content">
|
|
<div class="footer__section">
|
|
<h4>Dashboard</h4>
|
|
<p>Manage your blog posts and content from here.</p>
|
|
</div>
|
|
</div>
|
|
<div class="footer__bottom">
|
|
<p>© 2024. Self-hosted with care.</p>
|
|
</div>
|
|
</footer>
|
|
|
|
<script src="/static/js/app.js"></script>
|
|
<script>
|
|
// View switching
|
|
document.querySelectorAll('.sidebar-btn').forEach(btn => {
|
|
btn.addEventListener('click', (e) => {
|
|
const view = e.target.dataset.view;
|
|
|
|
// Update active button
|
|
document.querySelectorAll('.sidebar-btn').forEach(b => {
|
|
b.style.color = 'var(--md-sys-color-on-background)';
|
|
});
|
|
e.target.style.color = 'var(--md-sys-color-primary)';
|
|
|
|
// Update active view
|
|
document.querySelectorAll('.view-section').forEach(section => {
|
|
section.style.display = 'none';
|
|
});
|
|
document.getElementById(view + '-view').style.display = 'block';
|
|
|
|
// Load data for specific views
|
|
if (view === 'posts') {
|
|
loadUserPosts();
|
|
} else if (view === 'stats') {
|
|
loadStatistics();
|
|
} else if (view === 'editor') {
|
|
new PostEditor('post-editor');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Initialize editor on first load
|
|
new PostEditor('post-editor');
|
|
|
|
async function loadUserPosts() {
|
|
try {
|
|
const result = await api.get('/posts?page=1');
|
|
const postsList = document.getElementById('user-posts-list');
|
|
|
|
if (!result.data || result.data.length === 0) {
|
|
postsList.innerHTML = '<p>No posts yet. Start writing!</p>';
|
|
return;
|
|
}
|
|
|
|
let html = '<ul class="post-list">';
|
|
result.data.forEach(post => {
|
|
html += `
|
|
<li class="post-item">
|
|
<div style="display: flex; justify-content: space-between; align-items: start;">
|
|
<div style="flex: 1;">
|
|
<h3 class="post-title" style="margin: 0 0 8px 0;">
|
|
<a href="/post/${post.slug}">${post.title}</a>
|
|
</h3>
|
|
<div class="post-meta" style="font-size: 12px;">
|
|
<span>${new Date(post.created_at).toLocaleDateString()}</span>
|
|
${post.category ? `<span>${post.category}</span>` : ''}
|
|
</div>
|
|
</div>
|
|
<div style="display: flex; gap: 8px;">
|
|
<button onclick="editPost('${post.id}')" class="button button--secondary" style="height: 32px; padding: 0 12px; font-size: 12px;">Edit</button>
|
|
<button onclick="deletePost('${post.id}')" class="button button--tertiary" style="height: 32px; padding: 0 12px; font-size: 12px; color: var(--md-sys-color-error);">Delete</button>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
`;
|
|
});
|
|
html += '</ul>';
|
|
postsList.innerHTML = html;
|
|
} catch (error) {
|
|
document.getElementById('user-posts-list').innerHTML = '<p style="color: var(--md-sys-color-error);">Error loading posts</p>';
|
|
}
|
|
}
|
|
|
|
async function loadStatistics() {
|
|
try {
|
|
const result = await api.get('/posts?page=1');
|
|
const posts = result.data || [];
|
|
|
|
const total = posts.length;
|
|
const published = posts.filter(p => p.published).length;
|
|
const drafts = total - published;
|
|
|
|
document.getElementById('stat-total-posts').textContent = total;
|
|
document.getElementById('stat-published-posts').textContent = published;
|
|
document.getElementById('stat-draft-posts').textContent = drafts;
|
|
} catch (error) {
|
|
console.error('Error loading statistics:', error);
|
|
}
|
|
}
|
|
|
|
function editPost(postId) {
|
|
Toast.show('Edit functionality coming soon', 'info');
|
|
// TODO: Implement edit functionality
|
|
}
|
|
|
|
async function deletePost(postId) {
|
|
if (!confirm('Are you sure you want to delete this post?')) return;
|
|
|
|
try {
|
|
const result = await api.delete(`/posts/${postId}`);
|
|
if (result.success) {
|
|
Toast.show('Post deleted', 'success');
|
|
loadUserPosts();
|
|
}
|
|
} catch (error) {
|
|
Toast.show('Error deleting post', 'error');
|
|
}
|
|
}
|
|
|
|
async function handleLogout() {
|
|
try {
|
|
await api.post('/auth/logout', {});
|
|
Toast.show('Logged out', 'success');
|
|
setTimeout(() => window.location.href = '/', 1000);
|
|
} catch (error) {
|
|
Toast.show('Error logging out', 'error');
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|