Menu
Public repository / 8b66e18ce8cb51ca3e4124f89fd1429a1d4792f3
AkurAI-Mail / src/lib/webmail/folders.js
Latest change 10d19fe0941c186ec244d1f0e2af6b19200dcb0c - OLI-248: pure webmail logic as plain ES modules with JSDoc types; inline icon module by Ólafur Búi Ólafsson
/**
* @typedef {{ name: string, unread?: number, total?: number }} FolderSummary
* @typedef {{ name: string, path: string, depth: number, unread: number, total: number, children: FolderNode[] }} FolderNode
*/
/**
* Turns flat IMAP folder names ("Projects/2026") into a collapsible tree.
* @param {FolderSummary[]} folders
* @returns {FolderNode[]}
*/
export function buildFolderTree(folders) {
/** @type {FolderNode[]} */
const roots = [];
/** @type {Map<string, FolderNode>} */
const byPath = new Map();
for (const folder of folders) {
const segments = String(folder.name).split("/");
let path = "";
let siblings = roots;
segments.forEach((segment, depth) => {
path = path ? `${path}/${segment}` : segment;
let node = byPath.get(path);
if (!node) {
node = { name: segment, path, depth, unread: 0, total: 0, children: [] };
byPath.set(path, node);
siblings.push(node);
}
if (depth === segments.length - 1) {
node.unread = folder.unread ?? 0;
node.total = folder.total ?? 0;
}
siblings = node.children;
});
}
return roots;
}
/**
* Depth-first list of visible nodes; folders are expanded unless `expanded[path]` is false.
* @param {FolderNode[]} nodes
* @param {Record<string, boolean>} expanded
* @returns {FolderNode[]}
*/
export function visibleFolders(nodes, expanded) {
const rows = [];
for (const node of nodes) {
rows.push(node);
if (node.children.length && (expanded[node.path] ?? true)) rows.push(...visibleFolders(node.children, expanded));
}
return rows;
}