diff --git a/app/routers/board.py b/app/routers/board.py index 61ffdb6..3ce6e3c 100644 --- a/app/routers/board.py +++ b/app/routers/board.py @@ -179,12 +179,14 @@ def _load_workspace_pages(ws_cookie: str) -> list: for r in rows: is_folder = r["parent_section"] == "Workspace" title = r["title"] or "Untitled" + sub_children = _load_children(r["id"]) items.append({ "db_id": r["id"], "name": title, "id": f"page/{r['id']}", "icon": "📁" if is_folder else _file_icon(title, r["content_format"]), "is_folder": is_folder, - "children": _load_children(r["id"]), + "child_count": len(sub_children), + "children": sub_children, }) return items except (ValueError, Exception): @@ -202,12 +204,14 @@ def _load_children(parent_id: int) -> list: for r in rows: is_folder = r["parent_section"] == "Workspace" title = r["title"] or "Untitled" + sub_children = _load_children(r["id"]) children.append({ "db_id": r["id"], "name": title, "id": f"page/{r['id']}", "icon": "📁" if is_folder else _file_icon(title, r["content_format"]), "is_folder": is_folder, - "children": _load_children(r["id"]), + "child_count": len(sub_children), + "children": sub_children, }) return children diff --git a/app/routers/dashboard.py b/app/routers/dashboard.py index 048ecb5..6fca9a5 100644 --- a/app/routers/dashboard.py +++ b/app/routers/dashboard.py @@ -604,6 +604,7 @@ def _build_tree_children(conn, parent_id: int | None, ws_id: int) -> list: "content_format": r["content_format"] if not is_folder else None, "children": children, "has_children": len(children) > 0, + "child_count": len(children), }) return tree diff --git a/app/templates/base.html b/app/templates/base.html index 1cc24ea..0760a6e 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -111,6 +111,7 @@ data-id="{{ page.db_id }}" data-is-folder="{{ 'true' if page.is_folder else 'false' }}" data-depth="{{ depth }}" + :class="{ active: activeNodeId === {{ page.db_id }} }" draggable="true" @dragstart="dragStart($event, {{ page.db_id }})" @dragover.prevent="dragOver($event, {{ page.db_id }}, {{ 'true' if page.is_folder else 'false' }})" @@ -134,7 +135,7 @@ {{ page.name }} + title="Open folder">{{ page.name }}{% if page.child_count %} ({{ page.child_count }}){% endif %} {% else %} {{ page.name }} {% endif %} @@ -522,6 +523,10 @@ // ── Workspace tree context menu ── wsCtx: { visible: false, x: 0, y: 0, id: null, name: '', isFolder: false }, wsTouchTimer: null, + activeNodeId: (function() { + var m = window.location.search.match(/[?&]folder=(\d+)/); + return m ? parseInt(m[1]) : null; + })(), showWsContext(ev, id, name, isFolder) { this.wsCtx = { visible: true, x: ev.clientX, y: ev.clientY, id: id, name: name, isFolder: isFolder }; }, @@ -951,6 +956,14 @@ } } catch(e) {} }); + + // Auto-scroll sidebar to active folder + document.addEventListener('alpine:initialized', function() { + setTimeout(function() { + var active = document.querySelector('.sidebar-item.active'); + if (active) active.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); + }, 300); + }); {% block scripts %}{% endblock %} diff --git a/app/templates/local_workspace.html b/app/templates/local_workspace.html index e2b524a..9970312 100644 --- a/app/templates/local_workspace.html +++ b/app/templates/local_workspace.html @@ -113,6 +113,19 @@ .filter-chip:hover{background:var(--bg-hover);color:var(--text);} .filter-chip.active{background:var(--accent);color:#fff;border-color:var(--accent);} +/* Child count badge */ +.child-count{font-size:11px;color:var(--text-tertiary);margin-left:4px;} + +/* Inline rename */ +.inline-rename-input{background:var(--bg);border:1px solid var(--accent);border-radius:4px;color:var(--text);font-size:13px;padding:2px 6px;outline:none;min-width:100px;} + +/* Loading skeleton */ +.skeleton{background:linear-gradient(90deg,var(--bg-tertiary) 25%,var(--bg-hover) 50%,var(--bg-tertiary) 75%);background-size:200% 100%;animation:shimmer 1.5s infinite;border-radius:4px;height:16px;margin:4px 0;} +@keyframes shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}} + +/* Drag count badge */ +.drag-badge{position:fixed;pointer-events:none;z-index:999;background:var(--accent);color:#fff;font-size:12px;font-weight:700;padding:2px 8px;border-radius:10px;transform:translate(-50%,-50%);} + /* File preview tooltip */ .file-preview{position:fixed;z-index:300;background:#1a1a1a;background:var(--bg,#1a1a1a);border:1px solid var(--border-strong,#333);border-radius:10px;box-shadow:0 8px 30px rgba(0,0,0,.5);max-width:400px;min-width:200px;pointer-events:auto;} .file-preview-header{padding:8px 12px;font-size:12px;font-weight:600;color:var(--text-secondary,#888);border-bottom:1px solid var(--border,#333);} @@ -122,7 +135,10 @@