- New Projects view (projects.js): Lists all projects with cards - New ProjectView (projectView.js): Project dashboard with folder tree - Updated API client: Projects and Folders CRUD methods - New modals: NewProjectModal, NewFolderModal, MoveToFolderModal - Edit/Delete project functionality - Updated navigation: ProjectList -> ProjectView -> FolderView - Consistent dark theme styling Changes: - public/js/views/projects.js (NEW) - public/js/views/projectView.js (NEW) - public/js/api.js (added Projects/Folders API methods) - public/js/app.js (added navigation routes) - public/js/components/sidebar.js (added Projects link) - public/css/style.css (added project/folder styles)
141 lines
4.7 KiB
JavaScript
141 lines
4.7 KiB
JavaScript
// Projects List View - Shows all projects
|
|
|
|
import { api } from '../api.js';
|
|
|
|
export async function renderProjects(app) {
|
|
let projects = [];
|
|
|
|
try {
|
|
const result = await api.getProjects();
|
|
projects = result.projects || [];
|
|
} catch (e) {
|
|
app.showToast('Failed to load projects', 'error');
|
|
}
|
|
|
|
const appEl = document.getElementById('app');
|
|
|
|
function render() {
|
|
appEl.innerHTML = `
|
|
<header class="app-header">
|
|
<div class="logo">📝 SimpleNote</div>
|
|
<div class="header-actions">
|
|
<button class="btn btn-primary" onclick="window.showNewProjectModal()">+ New Project</button>
|
|
</div>
|
|
</header>
|
|
<div class="projects-page">
|
|
<div class="projects-header">
|
|
<h1>Projects</h1>
|
|
<p class="text-muted">Organize your documents into projects and folders</p>
|
|
</div>
|
|
<div class="projects-grid">
|
|
${projects.length === 0 ? `
|
|
<div class="empty-state">
|
|
<div class="icon">📋</div>
|
|
<h3>No projects yet</h3>
|
|
<p>Create your first project to get started</p>
|
|
<button class="btn btn-primary" onclick="window.showNewProjectModal()">+ Create Project</button>
|
|
</div>
|
|
` : projects.map(project => renderProjectCard(project)).join('')}
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
render();
|
|
}
|
|
|
|
function renderProjectCard(project) {
|
|
const createdDate = formatDate(project.createdAt);
|
|
const docCount = project.documentCount || 0;
|
|
const folderCount = project.folderCount || 0;
|
|
|
|
return `
|
|
<div class="project-card" onclick="window.app.navigate('project', {id: '${project.id}'})">
|
|
<div class="project-card-header">
|
|
<div class="project-icon">📋</div>
|
|
<div class="project-info">
|
|
<h3 class="project-name">${escapeHtml(project.name)}</h3>
|
|
${project.description ? `<p class="project-description">${escapeHtml(project.description)}</p>` : ''}
|
|
</div>
|
|
</div>
|
|
<div class="project-card-meta">
|
|
<span class="meta-item">📄 ${docCount} docs</span>
|
|
<span class="meta-item">📁 ${folderCount} folders</span>
|
|
<span class="meta-item">📅 ${createdDate}</span>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function escapeHtml(str) {
|
|
if (!str) return '';
|
|
const div = document.createElement('div');
|
|
div.textContent = str;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
function formatDate(dateStr) {
|
|
if (!dateStr) return '';
|
|
const date = new Date(dateStr);
|
|
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
|
}
|
|
|
|
// Global function: Show modal to create new project
|
|
window.showNewProjectModal = function() {
|
|
const backdrop = document.createElement('div');
|
|
backdrop.className = 'modal-backdrop';
|
|
backdrop.innerHTML = `
|
|
<div class="modal" style="min-width: 450px;">
|
|
<div class="modal-header">
|
|
<span>📋</span>
|
|
<h3>Create New Project</h3>
|
|
<button class="modal-close" onclick="this.closest('.modal-backdrop').remove()">✕</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="form-group">
|
|
<label for="new-project-name">Project Name</label>
|
|
<input type="text" id="new-project-name" class="form-control" placeholder="e.g., Backend Requirements">
|
|
</div>
|
|
<div class="form-group" style="margin-top: 16px;">
|
|
<label for="new-project-description">Description (optional)</label>
|
|
<textarea id="new-project-description" class="form-control" placeholder="Brief description of the project..." rows="3" style="resize: vertical;"></textarea>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button class="btn btn-ghost" onclick="this.closest('.modal-backdrop').remove()">Cancel</button>
|
|
<button class="btn btn-primary" id="create-project-btn">Create Project</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
document.body.appendChild(backdrop);
|
|
|
|
const nameInput = document.getElementById('new-project-name');
|
|
const descInput = document.getElementById('new-project-description');
|
|
const createBtn = document.getElementById('create-project-btn');
|
|
|
|
createBtn.onclick = async () => {
|
|
const name = nameInput.value.trim();
|
|
if (!name) {
|
|
window.app.showToast('Please enter a project name', 'error');
|
|
return;
|
|
}
|
|
try {
|
|
await api.createProject({
|
|
name,
|
|
description: descInput.value.trim()
|
|
});
|
|
backdrop.remove();
|
|
window.app.showToast('Project created successfully', 'success');
|
|
window.app.navigate('projects');
|
|
} catch (e) {
|
|
window.app.showToast('Failed to create project: ' + e.message, 'error');
|
|
}
|
|
};
|
|
|
|
backdrop.onclick = (e) => {
|
|
if (e.target === backdrop) backdrop.remove();
|
|
};
|
|
|
|
nameInput.focus();
|
|
};
|