first commit, mate!
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
<!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>
|
||||
Reference in New Issue
Block a user