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:
@@ -1239,10 +1239,90 @@ ul, ol {
|
|||||||
to { transform: rotate(360deg); }
|
to { transform: rotate(360deg); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* === Mobile Navigation Drawer === */
|
||||||
|
.mobile-nav-btn {
|
||||||
|
display: none;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-size: 1.25rem;
|
||||||
|
transition: var(--transition-fast);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-nav-btn:hover {
|
||||||
|
background: var(--color-hover);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: calc(var(--z-sidebar) - 1);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay.active {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-close-btn {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: var(--space-3);
|
||||||
|
right: var(--space-3);
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-size: 1.25rem;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-close-btn:hover {
|
||||||
|
background: var(--color-hover);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
/* === Responsive === */
|
/* === Responsive === */
|
||||||
@media (max-width: 1024px) {
|
@media (max-width: 1024px) {
|
||||||
.sidebar {
|
.sidebar {
|
||||||
display: none;
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: var(--z-sidebar);
|
||||||
|
transform: translateX(-100%);
|
||||||
|
transition: transform 0.25s ease;
|
||||||
|
box-shadow: var(--shadow-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar.mobile-open {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-scroll {
|
||||||
|
padding-top: 56px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-close-btn {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-nav-btn {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-overlay {
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.doc-sidebar {
|
.doc-sidebar {
|
||||||
@@ -1276,22 +1356,300 @@ ul, ol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content-body {
|
.content-body {
|
||||||
padding: var(--space-4);
|
padding: var(--space-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.doc-grid {
|
.doc-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
gap: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.doc-card {
|
||||||
|
padding: var(--space-4);
|
||||||
|
min-height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doc-card-actions {
|
||||||
|
opacity: 1;
|
||||||
|
position: static;
|
||||||
|
margin-top: var(--space-2);
|
||||||
|
display: flex;
|
||||||
|
gap: var(--space-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
min-width: auto;
|
min-width: auto;
|
||||||
margin: var(--space-4);
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-backdrop {
|
||||||
|
padding: 0;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
padding: var(--space-4);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: var(--space-4);
|
||||||
|
gap: var(--space-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-card {
|
.login-card {
|
||||||
margin: var(--space-4);
|
margin: var(--space-4);
|
||||||
padding: var(--space-6);
|
padding: var(--space-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* === Projects Page Mobile === */
|
||||||
|
.projects-page {
|
||||||
|
padding: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.projects-header {
|
||||||
|
margin-bottom: var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.projects-header h1 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.projects-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-card {
|
||||||
|
padding: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-card-header {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-icon {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-name {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Header Mobile === */
|
||||||
|
.app-header {
|
||||||
|
padding: var(--space-2) var(--space-3);
|
||||||
|
gap: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-header .logo {
|
||||||
|
font-size: 1rem;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions .btn {
|
||||||
|
padding: var(--space-2) var(--space-3);
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Content Header Mobile === */
|
||||||
|
.content-header {
|
||||||
|
padding: var(--space-3) var(--space-4);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-header-left {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-1);
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-header-left h1 {
|
||||||
|
font-size: 1.125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-header-right {
|
||||||
|
width: 100%;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box-inline {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box-inline input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Editor Mobile === */
|
||||||
|
.editor-container {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-header {
|
||||||
|
padding: var(--space-3) var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-form {
|
||||||
|
padding: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-toolbar {
|
||||||
|
overflow-x: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
gap: var(--space-1);
|
||||||
|
padding: var(--space-2);
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-btn {
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-separator {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-tabs {
|
||||||
|
margin-left: auto;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn {
|
||||||
|
padding: var(--space-2) var(--space-3);
|
||||||
|
min-height: 44px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group textarea {
|
||||||
|
min-height: 200px;
|
||||||
|
font-size: 16px; /* Prevents zoom on iOS */
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input,
|
||||||
|
.form-group select {
|
||||||
|
min-height: 44px;
|
||||||
|
font-size: 16px; /* Prevents zoom on iOS */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Doc Card Mobile === */
|
||||||
|
.doc-card-header {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doc-title {
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doc-tags {
|
||||||
|
margin-top: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.doc-meta {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Touch Targets === */
|
||||||
|
.btn {
|
||||||
|
min-height: 44px;
|
||||||
|
min-width: 44px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon-only {
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-item {
|
||||||
|
min-height: 44px;
|
||||||
|
padding: var(--space-2) var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree-item .tree-action {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-item {
|
||||||
|
min-height: 44px;
|
||||||
|
padding: var(--space-2) var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-link {
|
||||||
|
min-height: 44px;
|
||||||
|
padding: var(--space-2) var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.doc-card {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Empty State Mobile === */
|
||||||
|
.empty-state {
|
||||||
|
padding: var(--space-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Breadcrumbs Mobile === */
|
||||||
|
.breadcrumb-nav {
|
||||||
|
margin-left: 0;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* === Toast Mobile === */
|
||||||
|
#toast-container {
|
||||||
|
bottom: var(--space-4);
|
||||||
|
right: var(--space-4);
|
||||||
|
left: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toast {
|
||||||
|
min-width: auto;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure minimum touch target size */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
a, button, [role="button"] {
|
||||||
|
min-height: 44px;
|
||||||
|
min-width: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, select, textarea {
|
||||||
|
font-size: 16px; /* Prevents iOS zoom */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* === Projects Page === */
|
/* === Projects Page === */
|
||||||
|
|||||||
@@ -25,70 +25,36 @@ export function renderSidebar({ libraries, tags, selectedLibrary, selectedTag, o
|
|||||||
.join('');
|
.join('');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Store callbacks in a way that's safe and doesn't rely on inline script execution
|
|
||||||
const callbacks = {
|
|
||||||
onSelectLibrary,
|
|
||||||
onSelectTag,
|
|
||||||
onHome
|
|
||||||
};
|
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<aside class="sidebar">
|
<div class="sidebar-scroll">
|
||||||
<div class="sidebar-scroll">
|
<div class="sidebar-section">
|
||||||
<div class="sidebar-section">
|
<h3>📚 Libraries</h3>
|
||||||
<h3>📚 Libraries</h3>
|
<div class="library-tree">
|
||||||
<div class="library-tree">
|
<div class="tree-item ${!selectedLibrary ? 'active' : ''}" data-action="home">
|
||||||
<div class="tree-item ${!selectedLibrary ? 'active' : ''}" data-action="home">
|
<span class="icon">🏠</span>
|
||||||
<span class="icon">🏠</span>
|
<span class="label">All Documents</span>
|
||||||
<span class="label">All Documents</span>
|
|
||||||
</div>
|
|
||||||
${buildLibraryTree(libraries)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
${buildLibraryTree(libraries)}
|
||||||
<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>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
<div class="sidebar-section">
|
||||||
<script>
|
<h3>🏷️ Tags</h3>
|
||||||
(function() {
|
<div class="tag-list">
|
||||||
var callbacks = window.__sidebarCallbacks;
|
${tags.map(tag => `
|
||||||
document.querySelectorAll('[data-action="home"]').forEach(function(el) {
|
<div class="tag-item ${selectedTag === tag.name ? 'active' : ''}" data-action="tag" data-tag="${escapeHtml(tag.name)}">
|
||||||
el.addEventListener('click', function(e) {
|
<span>#${escapeHtml(tag.name)}</span>
|
||||||
e.stopPropagation();
|
<span class="tag-count">${tag.count}</span>
|
||||||
if (callbacks && callbacks.onHome) callbacks.onHome();
|
</div>
|
||||||
});
|
`).join('')}
|
||||||
});
|
</div>
|
||||||
document.querySelectorAll('[data-action="library"]').forEach(function(el) {
|
</div>
|
||||||
el.addEventListener('click', function(e) {
|
<div class="quick-links">
|
||||||
e.stopPropagation();
|
<a class="quick-link" data-action="home">📋 All Documents</a>
|
||||||
var id = this.getAttribute('data-library-id');
|
<a class="quick-link" href="#" onclick="window.app.navigate('projects'); return false;">📂 Projects</a>
|
||||||
if (callbacks && callbacks.onSelectLibrary) callbacks.onSelectLibrary(id);
|
<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>
|
||||||
document.querySelectorAll('[data-action="tag"]').forEach(function(el) {
|
</div>
|
||||||
el.addEventListener('click', function(e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
var tag = this.getAttribute('data-tag');
|
|
||||||
if (callbacks && callbacks.onSelectTag) callbacks.onSelectTag(tag);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,29 +77,33 @@ export async function renderDashboard(app) {
|
|||||||
|
|
||||||
appEl.innerHTML = `
|
appEl.innerHTML = `
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
|
<button class="mobile-nav-btn" onclick="toggleMobileSidebar()" title="Menu">☰</button>
|
||||||
<div class="logo">📝 SimpleNote</div>
|
<div class="logo">📝 SimpleNote</div>
|
||||||
<div class="search-box">
|
<div class="search-box">
|
||||||
<span class="icon">🔍</span>
|
<span class="icon">🔍</span>
|
||||||
<input type="text" id="search-input" placeholder="Search documents..." value="${searchQuery}">
|
<input type="text" id="search-input" placeholder="Search documents..." value="${searchQuery}">
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<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>
|
||||||
<button class="btn btn-ghost" onclick="window.showNewLibraryModal()">📁 New Library</button>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
<div class="sidebar-overlay" onclick="closeMobileSidebar()"></div>
|
||||||
<div class="app-layout">
|
<div class="app-layout">
|
||||||
${renderSidebar({
|
<aside class="sidebar" id="sidebar">
|
||||||
libraries,
|
<button class="sidebar-close-btn" onclick="closeMobileSidebar()">✕</button>
|
||||||
tags,
|
${renderSidebar({
|
||||||
selectedLibrary,
|
libraries,
|
||||||
selectedTag,
|
tags,
|
||||||
...sidebarCallbacks
|
selectedLibrary,
|
||||||
})}
|
selectedTag,
|
||||||
|
...sidebarCallbacks
|
||||||
|
})}
|
||||||
|
</aside>
|
||||||
<main class="main-content">
|
<main class="main-content">
|
||||||
<div class="content-header">
|
<div class="content-header">
|
||||||
<h1>${selectedLibrary ? getLibraryName(libraries, selectedLibrary) : selectedTag ? `#${selectedTag}` : 'All Documents'}</h1>
|
<h1>${selectedLibrary ? getLibraryName(libraries, selectedLibrary) : selectedTag ? `#${selectedTag}` : 'All Documents'}</h1>
|
||||||
<div class="header-actions">
|
<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>
|
</div>
|
||||||
<div class="content-body">
|
<div class="content-body">
|
||||||
@@ -120,12 +124,54 @@ export async function renderDashboard(app) {
|
|||||||
</div>
|
</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
|
// Event listeners
|
||||||
const searchInput = document.getElementById('search-input');
|
const searchInput = document.getElementById('search-input');
|
||||||
searchInput.oninput = (e) => {
|
searchInput.oninput = (e) => {
|
||||||
searchQuery = e.target.value;
|
searchQuery = e.target.value;
|
||||||
render();
|
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();
|
render();
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ export async function renderProjectView(app) {
|
|||||||
|
|
||||||
appEl.innerHTML = `
|
appEl.innerHTML = `
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
|
<button class="mobile-nav-btn" onclick="toggleMobileSidebar()" title="Menu">☰</button>
|
||||||
<div class="logo">📝 SimpleNote</div>
|
<div class="logo">📝 SimpleNote</div>
|
||||||
<div class="breadcrumb-nav">
|
<div class="breadcrumb-nav">
|
||||||
<span class="breadcrumb-link" onclick="window.app.navigate('projects')">Projects</span>
|
<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>
|
<button class="btn btn-ghost" onclick="window.confirmDeleteProject('${project.id}')" title="Delete Project">🗑️</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
<div class="sidebar-overlay" onclick="closeMobileSidebar()"></div>
|
||||||
<div class="app-layout">
|
<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-scroll">
|
||||||
<div class="sidebar-section">
|
<div class="sidebar-section">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
@@ -130,7 +133,7 @@ export async function renderProjectView(app) {
|
|||||||
<span class="icon">🔍</span>
|
<span class="icon">🔍</span>
|
||||||
<input type="text" id="search-input" placeholder="Search documents..." value="${escapeHtml(searchQuery)}">
|
<input type="text" id="search-input" placeholder="Search documents..." value="${escapeHtml(searchQuery)}">
|
||||||
</div>
|
</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>
|
</div>
|
||||||
<div class="content-body">
|
<div class="content-body">
|
||||||
@@ -155,6 +158,25 @@ export async function renderProjectView(app) {
|
|||||||
attachEventListeners();
|
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() {
|
function attachEventListeners() {
|
||||||
// Search
|
// Search
|
||||||
const searchInput = document.getElementById('search-input');
|
const searchInput = document.getElementById('search-input');
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export async function renderProjects(app) {
|
|||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
<div class="logo">📝 SimpleNote</div>
|
<div class="logo">📝 SimpleNote</div>
|
||||||
<div class="header-actions">
|
<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>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="projects-page">
|
<div class="projects-page">
|
||||||
|
|||||||
Reference in New Issue
Block a user