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
This commit is contained in:
@@ -25,70 +25,36 @@ export function renderSidebar({ libraries, tags, selectedLibrary, selectedTag, o
|
||||
.join('');
|
||||
};
|
||||
|
||||
// Store callbacks in a way that's safe and doesn't rely on inline script execution
|
||||
const callbacks = {
|
||||
onSelectLibrary,
|
||||
onSelectTag,
|
||||
onHome
|
||||
};
|
||||
|
||||
return `
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-scroll">
|
||||
<div class="sidebar-section">
|
||||
<h3>📚 Libraries</h3>
|
||||
<div class="library-tree">
|
||||
<div class="tree-item ${!selectedLibrary ? 'active' : ''}" data-action="home">
|
||||
<span class="icon">🏠</span>
|
||||
<span class="label">All Documents</span>
|
||||
</div>
|
||||
${buildLibraryTree(libraries)}
|
||||
<div class="sidebar-scroll">
|
||||
<div class="sidebar-section">
|
||||
<h3>📚 Libraries</h3>
|
||||
<div class="library-tree">
|
||||
<div class="tree-item ${!selectedLibrary ? 'active' : ''}" data-action="home">
|
||||
<span class="icon">🏠</span>
|
||||
<span class="label">All Documents</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-section">
|
||||
<h3>🏷️ Tags</h3>
|
||||
<div class="tag-list">
|
||||
${tags.map(tag => `
|
||||
<div class="tag-item ${selectedTag === tag.name ? 'active' : ''}" data-action="tag" data-tag="${escapeHtml(tag.name)}">
|
||||
<span>#${escapeHtml(tag.name)}</span>
|
||||
<span class="tag-count">${tag.count}</span>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
<div class="quick-links">
|
||||
<a class="quick-link" data-action="home">📋 All Documents</a>
|
||||
<a class="quick-link" href="#" onclick="window.app.navigate('projects'); return false;">📂 Projects</a>
|
||||
<a class="quick-link" href="#" onclick="window.showNewDocModal(); return false;">📄 New Document</a>
|
||||
<a class="quick-link" href="#" onclick="window.showNewLibraryModal(); return false;">📁 New Library</a>
|
||||
${buildLibraryTree(libraries)}
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<script>
|
||||
(function() {
|
||||
var callbacks = window.__sidebarCallbacks;
|
||||
document.querySelectorAll('[data-action="home"]').forEach(function(el) {
|
||||
el.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
if (callbacks && callbacks.onHome) callbacks.onHome();
|
||||
});
|
||||
});
|
||||
document.querySelectorAll('[data-action="library"]').forEach(function(el) {
|
||||
el.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
var id = this.getAttribute('data-library-id');
|
||||
if (callbacks && callbacks.onSelectLibrary) callbacks.onSelectLibrary(id);
|
||||
});
|
||||
});
|
||||
document.querySelectorAll('[data-action="tag"]').forEach(function(el) {
|
||||
el.addEventListener('click', function(e) {
|
||||
e.stopPropagation();
|
||||
var tag = this.getAttribute('data-tag');
|
||||
if (callbacks && callbacks.onSelectTag) callbacks.onSelectTag(tag);
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
<div class="sidebar-section">
|
||||
<h3>🏷️ Tags</h3>
|
||||
<div class="tag-list">
|
||||
${tags.map(tag => `
|
||||
<div class="tag-item ${selectedTag === tag.name ? 'active' : ''}" data-action="tag" data-tag="${escapeHtml(tag.name)}">
|
||||
<span>#${escapeHtml(tag.name)}</span>
|
||||
<span class="tag-count">${tag.count}</span>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
<div class="quick-links">
|
||||
<a class="quick-link" data-action="home">📋 All Documents</a>
|
||||
<a class="quick-link" href="#" onclick="window.app.navigate('projects'); return false;">📂 Projects</a>
|
||||
<a class="quick-link" href="#" onclick="window.showNewDocModal(); return false;">📄 New Document</a>
|
||||
<a class="quick-link" href="#" onclick="window.showNewLibraryModal(); return false;">📁 New Library</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,29 +77,33 @@ export async function renderDashboard(app) {
|
||||
|
||||
appEl.innerHTML = `
|
||||
<header class="app-header">
|
||||
<button class="mobile-nav-btn" onclick="toggleMobileSidebar()" title="Menu">☰</button>
|
||||
<div class="logo">📝 SimpleNote</div>
|
||||
<div class="search-box">
|
||||
<span class="icon">🔍</span>
|
||||
<input type="text" id="search-input" placeholder="Search documents..." value="${searchQuery}">
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button class="btn btn-primary" onclick="window.showNewDocModal()">+ New Document</button>
|
||||
<button class="btn btn-ghost" onclick="window.showNewLibraryModal()">📁 New Library</button>
|
||||
<button class="btn btn-primary" onclick="window.showNewDocModal()">+ New</button>
|
||||
</div>
|
||||
</header>
|
||||
<div class="sidebar-overlay" onclick="closeMobileSidebar()"></div>
|
||||
<div class="app-layout">
|
||||
${renderSidebar({
|
||||
libraries,
|
||||
tags,
|
||||
selectedLibrary,
|
||||
selectedTag,
|
||||
...sidebarCallbacks
|
||||
})}
|
||||
<aside class="sidebar" id="sidebar">
|
||||
<button class="sidebar-close-btn" onclick="closeMobileSidebar()">✕</button>
|
||||
${renderSidebar({
|
||||
libraries,
|
||||
tags,
|
||||
selectedLibrary,
|
||||
selectedTag,
|
||||
...sidebarCallbacks
|
||||
})}
|
||||
</aside>
|
||||
<main class="main-content">
|
||||
<div class="content-header">
|
||||
<h1>${selectedLibrary ? getLibraryName(libraries, selectedLibrary) : selectedTag ? `#${selectedTag}` : 'All Documents'}</h1>
|
||||
<div class="header-actions">
|
||||
<button class="btn btn-primary" onclick="window.showNewDocModal()">+ New Document</button>
|
||||
<button class="btn btn-primary" onclick="window.showNewDocModal()">+ New</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-body">
|
||||
@@ -120,12 +124,54 @@ export async function renderDashboard(app) {
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Mobile sidebar functions
|
||||
window.toggleMobileSidebar = function() {
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const overlay = document.querySelector('.sidebar-overlay');
|
||||
if (sidebar) {
|
||||
sidebar.classList.toggle('mobile-open');
|
||||
if (overlay) overlay.classList.toggle('active');
|
||||
}
|
||||
};
|
||||
|
||||
window.closeMobileSidebar = function() {
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const overlay = document.querySelector('.sidebar-overlay');
|
||||
if (sidebar) {
|
||||
sidebar.classList.remove('mobile-open');
|
||||
if (overlay) overlay.classList.remove('active');
|
||||
}
|
||||
};
|
||||
|
||||
// Event listeners
|
||||
const searchInput = document.getElementById('search-input');
|
||||
searchInput.oninput = (e) => {
|
||||
searchQuery = e.target.value;
|
||||
render();
|
||||
};
|
||||
|
||||
// Sidebar item listeners
|
||||
document.querySelectorAll('[data-action="home"]').forEach(el => {
|
||||
el.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
sidebarCallbacks.onHome();
|
||||
closeMobileSidebar();
|
||||
});
|
||||
});
|
||||
document.querySelectorAll('[data-action="library"]').forEach(el => {
|
||||
el.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
sidebarCallbacks.onSelectLibrary(el.getAttribute('data-library-id'));
|
||||
closeMobileSidebar();
|
||||
});
|
||||
});
|
||||
document.querySelectorAll('[data-action="tag"]').forEach(el => {
|
||||
el.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
sidebarCallbacks.onSelectTag(el.getAttribute('data-tag'));
|
||||
closeMobileSidebar();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render();
|
||||
|
||||
@@ -74,6 +74,7 @@ export async function renderProjectView(app) {
|
||||
|
||||
appEl.innerHTML = `
|
||||
<header class="app-header">
|
||||
<button class="mobile-nav-btn" onclick="toggleMobileSidebar()" title="Menu">☰</button>
|
||||
<div class="logo">📝 SimpleNote</div>
|
||||
<div class="breadcrumb-nav">
|
||||
<span class="breadcrumb-link" onclick="window.app.navigate('projects')">Projects</span>
|
||||
@@ -85,8 +86,10 @@ export async function renderProjectView(app) {
|
||||
<button class="btn btn-ghost" onclick="window.confirmDeleteProject('${project.id}')" title="Delete Project">🗑️</button>
|
||||
</div>
|
||||
</header>
|
||||
<div class="sidebar-overlay" onclick="closeMobileSidebar()"></div>
|
||||
<div class="app-layout">
|
||||
<aside class="sidebar project-sidebar">
|
||||
<aside class="sidebar project-sidebar" id="sidebar">
|
||||
<button class="sidebar-close-btn" onclick="closeMobileSidebar()">✕</button>
|
||||
<div class="sidebar-scroll">
|
||||
<div class="sidebar-section">
|
||||
<div class="section-header">
|
||||
@@ -130,7 +133,7 @@ export async function renderProjectView(app) {
|
||||
<span class="icon">🔍</span>
|
||||
<input type="text" id="search-input" placeholder="Search documents..." value="${escapeHtml(searchQuery)}">
|
||||
</div>
|
||||
<button class="btn btn-primary" onclick="window.showNewDocModal('${projectId}', '${selectedFolderId || ''}')">+ New Document</button>
|
||||
<button class="btn btn-primary" onclick="window.showNewDocModal('${projectId}', '${selectedFolderId || ''}')">+ New</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-body">
|
||||
@@ -155,6 +158,25 @@ export async function renderProjectView(app) {
|
||||
attachEventListeners();
|
||||
}
|
||||
|
||||
// Mobile sidebar functions
|
||||
window.toggleMobileSidebar = function() {
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const overlay = document.querySelector('.sidebar-overlay');
|
||||
if (sidebar) {
|
||||
sidebar.classList.toggle('mobile-open');
|
||||
if (overlay) overlay.classList.toggle('active');
|
||||
}
|
||||
};
|
||||
|
||||
window.closeMobileSidebar = function() {
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const overlay = document.querySelector('.sidebar-overlay');
|
||||
if (sidebar) {
|
||||
sidebar.classList.remove('mobile-open');
|
||||
if (overlay) overlay.classList.remove('active');
|
||||
}
|
||||
};
|
||||
|
||||
function attachEventListeners() {
|
||||
// Search
|
||||
const searchInput = document.getElementById('search-input');
|
||||
|
||||
@@ -19,7 +19,7 @@ export async function renderProjects(app) {
|
||||
<header class="app-header">
|
||||
<div class="logo">📝 SimpleNote</div>
|
||||
<div class="header-actions">
|
||||
<button class="btn btn-primary" onclick="window.showNewProjectModal()">+ New Project</button>
|
||||
<button class="btn btn-primary" onclick="window.showNewProjectModal()">+ New</button>
|
||||
</div>
|
||||
</header>
|
||||
<div class="projects-page">
|
||||
|
||||
Reference in New Issue
Block a user