Files
simplenote-web/public/js/views/projects.js
Hiro 8f7ad3f673 feat: improve mobile responsiveness
- Add mobile navigation drawer with hamburger menu
- Sidebar slides in as overlay on mobile (<768px)
- Close button inside sidebar for mobile
- Ensure touch targets are at least 44px on mobile
- Make modals full-screen on mobile
- Editor toolbar scrolls horizontally on mobile
- Improve spacing and typography for small screens
- Keep dark theme consistent across breakpoints
- Projects page cards stack vertically on mobile
- Document cards full-width on mobile
2026-03-28 14:00:05 +00:00

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</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();
};