diff --git a/app/routers/board.py b/app/routers/board.py index 96a5980..ccfe352 100644 --- a/app/routers/board.py +++ b/app/routers/board.py @@ -140,6 +140,27 @@ def _build_page_tree(conn, parent_id: int | None, ws_key: str, depth: int = 0, m return items +def _file_icon(name: str) -> str: + """Map file extension to emoji icon.""" + import re + n = name.lower() + if re.search(r'\.(png|jpe?g|gif|webp|svg|bmp|ico)$', n): return '🖼️' + if n.endswith('.pdf'): return '📕' + if re.search(r'\.(md|markdown)$', n): return '📝' + if n.endswith('.py'): return '🐍' + if re.search(r'\.(js|jsx|ts|tsx)$', n): return '📜' + if re.search(r'\.(html?|xml)$', n): return '🌐' + if n.endswith('.css'): return '🎨' + if n.endswith('.json'): return '📋' + if n.endswith('.sql'): return '🗃️' + if re.search(r'\.(sh|bash|zsh)$', n): return '💻' + if n.endswith('.ps1'): return '⚡' + if re.search(r'\.(rs|go|java|rb|php|c|cpp|h|swift|kt|scala|r)$', n): return '📜' + if re.search(r'\.(txt|log)$', n): return '📄' + if re.search(r'\.(zip|tar|gz|rar|7z)$', n): return '📦' + return '📄' + + def _load_workspace_pages(ws_cookie: str) -> list: """Load top-level pages with children for the active workspace.""" if not ws_cookie: @@ -153,11 +174,13 @@ def _load_workspace_pages(ws_cookie: str) -> list: ).fetchall() items = [] for r in rows: + is_folder = r["parent_section"] == "Workspace" + title = r["title"] or "Untitled" items.append({ - "db_id": r["id"], "name": r["title"] or "Untitled", + "db_id": r["id"], "name": title, "id": f"page/{r['id']}", - "icon": "📁" if r["parent_section"] == "Workspace" else "📄", - "is_folder": r["parent_section"] == "Workspace", + "icon": "📁" if is_folder else _file_icon(title), + "is_folder": is_folder, "children": _load_children(r["id"]), }) return items @@ -174,11 +197,13 @@ def _load_children(parent_id: int) -> list: ).fetchall() children = [] for r in rows: + is_folder = r["parent_section"] == "Workspace" + title = r["title"] or "Untitled" children.append({ - "db_id": r["id"], "name": r["title"] or "Untitled", + "db_id": r["id"], "name": title, "id": f"page/{r['id']}", - "icon": "📁" if r["parent_section"] == "Workspace" else "📄", - "is_folder": r["parent_section"] == "Workspace", + "icon": "📁" if is_folder else _file_icon(title), + "is_folder": is_folder, "children": _load_children(r["id"]), }) return children diff --git a/app/templates/local_workspace.html b/app/templates/local_workspace.html index 128e24e..628c07a 100644 --- a/app/templates/local_workspace.html +++ b/app/templates/local_workspace.html @@ -107,6 +107,12 @@ .search-clear{background:none;border:none;color:var(--text-tertiary);cursor:pointer;font-size:16px;padding:2px 4px;border-radius:3px;} .search-clear:hover{color:var(--text);background:var(--bg-hover);} +/* Filter chips */ +.filter-chips{display:flex;gap:6px;margin-bottom:10px;flex-wrap:wrap;} +.filter-chip{padding:4px 10px;background:var(--bg-tertiary);border:1px solid var(--border);border-radius:6px;font-size:12px;color:var(--text-secondary);cursor:pointer;transition:all 150ms;} +.filter-chip:hover{background:var(--bg-hover);color:var(--text);} +.filter-chip.active{background:var(--accent);color:#fff;border-color:var(--accent);} + /* 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);} @@ -174,6 +180,15 @@ + +
+ + + + + +
+