feat: enhance notes list UI with improved visual hierarchy

- Added new folder creation endpoint with support for path or parent/name parameters
- Updated notes list styling with consistent row cards and active state indicators
- Improved theme-aware color variables for better light/dark mode contrast
- Added visual depth with subtle gradient overlays and active item highlighting
- Implemented consistent styling between virtual and standard note list views
- Enhanced new note button styling for better visibility
This commit is contained in:
2025-10-24 13:08:13 -04:00
parent 08a2d05dad
commit 83603e2d97
19 changed files with 1230 additions and 104 deletions
+55
View File
@@ -27,6 +27,8 @@ export function setupRenameFolderEndpoint(app, vaultDir, broadcastVaultEvent, me
if (!oldPath || typeof oldPath !== 'string') {
return res.status(400).json({ error: 'Missing or invalid oldPath' });
}
if (!newName || typeof newName !== 'string') {
return res.status(400).json({ error: 'Missing or invalid newName' });
}
@@ -202,6 +204,59 @@ export function setupDeleteFolderEndpoint(app, vaultDir, broadcastVaultEvent, me
});
}
// ============================================================================
// ENDPOINT 7: /api/folders (POST) - Create a folder (supports { path } or { parentPath, newFolderName })
// ============================================================================
export function setupCreateFolderEndpoint(app, vaultDir, broadcastVaultEvent, metadataCache) {
app.post('/api/folders', express.json(), async (req, res) => {
try {
const body = req.body || {};
let rel = '';
if (typeof body.path === 'string' && body.path.trim()) {
rel = body.path.trim();
} else if (typeof body.parentPath === 'string' && typeof body.newFolderName === 'string') {
const parent = body.parentPath.replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
const name = body.newFolderName.trim();
if (!name) {
return res.status(400).json({ error: 'New folder name cannot be empty' });
}
rel = parent ? `${parent}/${name}` : name;
} else {
return res.status(400).json({ error: 'Missing path or (parentPath, newFolderName)' });
}
const sanitizedRel = String(rel).replace(/\\/g, '/').replace(/^\/+|\/+$/g, '');
if (!sanitizedRel) {
return res.status(400).json({ error: 'Invalid folder path' });
}
const abs = path.join(vaultDir, sanitizedRel);
const vaultAbs = path.resolve(vaultDir);
const absResolved = path.resolve(abs);
if (!absResolved.startsWith(vaultAbs)) {
return res.status(400).json({ error: 'Path escapes vault root' });
}
try {
await fs.promises.mkdir(absResolved, { recursive: true });
} catch (mkErr) {
console.error('[POST /api/folders] mkdir failed:', mkErr);
return res.status(500).json({ error: 'Failed to create folder' });
}
if (metadataCache) metadataCache.clear();
if (broadcastVaultEvent) {
broadcastVaultEvent({ event: 'folder-create', path: sanitizedRel, timestamp: Date.now() });
}
return res.json({ success: true, path: sanitizedRel });
} catch (error) {
console.error('[POST /api/folders] Unexpected error:', error);
return res.status(500).json({ error: 'Internal server error' });
}
});
}
// ============================================================================
// ENDPOINT 1: /api/vault/metadata - with cache read-through and monitoring
// ============================================================================
+5 -1
View File
@@ -32,7 +32,8 @@ import {
setupDeferredIndexing,
setupCreateNoteEndpoint,
setupRenameFolderEndpoint,
setupDeleteFolderEndpoint
setupDeleteFolderEndpoint,
setupCreateFolderEndpoint
} from './index-phase3-patch.mjs';
const __filename = fileURLToPath(import.meta.url);
@@ -1532,6 +1533,9 @@ setupRenameFolderEndpoint(app, vaultDir, broadcastVaultEvent, metadataCache);
// Setup delete folder endpoint (must be before catch-all)
setupDeleteFolderEndpoint(app, vaultDir, broadcastVaultEvent, metadataCache);
// Setup create folder endpoint (must be before catch-all)
setupCreateFolderEndpoint(app, vaultDir, broadcastVaultEvent, metadataCache);
app.get('/', sendIndex);
app.use((req, res) => {
if (req.path.startsWith('/api/')) {