Fix navigation to not display the whole structure, just the current root.

This commit is contained in:
Timothy Farrell 2026-05-09 03:23:29 +00:00
parent b8947af2db
commit eaf574231c
3 changed files with 59 additions and 53 deletions

View File

@ -51,7 +51,7 @@
padding: 10px; padding: 10px;
} }
.play-btn:hover { color: rgba(255, 255, 255, 1); transform: scale(1.1); } .play-btn:hover { color: rgba(255, 255, 255, 1); transform: scale(1.1); }
/q .hidden { display: none; } .hidden { display: none; }
#sidebar { #sidebar {
position: fixed; position: fixed;
top: 0; top: 0;
@ -72,6 +72,7 @@
display: block; display: block;
padding: 4px 8px; padding: 4px 8px;
border-radius: 4px; border-radius: 4px;
text-wrap-mode: nowrap;
} }
#sidebar a:hover { #sidebar a:hover {
background: #3a3a3a; background: #3a3a3a;
@ -185,6 +186,7 @@
} }
} else if (e.key.toLowerCase() === 'i') { } else if (e.key.toLowerCase() === 'i') {
document.getElementById('sidebar').classList.toggle('hidden'); document.getElementById('sidebar').classList.toggle('hidden');
document.getElementById('sidebar-toggle').classList.toggle('collapsed');
} }
}); });

97
main.py
View File

@ -705,7 +705,7 @@ def _render_folder_index_html(
current_order: str | None = None, current_order: str | None = None,
current_delay: int | None = None, current_delay: int | None = None,
) -> str: ) -> str:
"""Render a folder index sidebar showing the full tree from root. """Render a folder index sidebar showing only the current folder's contents.
Args: Args:
current_path: The currently viewed file path (for highlighting). current_path: The currently viewed file path (for highlighting).
@ -716,6 +716,30 @@ def _render_folder_index_html(
HTML string for the folder index sidebar. HTML string for the folder index sidebar.
""" """
all_paths = _collect_zip_paths() all_paths = _collect_zip_paths()
# Determine the folder to display:
# - None/"" → root
# - ends with "/" → that folder
# - file path → parent folder
if not current_path:
folder_prefix = ""
elif current_path.endswith("/"):
folder_prefix = current_path
else:
# current_path is a file — show its parent folder
slash_idx = current_path.rfind("/")
folder_prefix = current_path[: slash_idx + 1] if slash_idx >= 0 else ""
folders: set[str] = set()
files: set[str] = set()
for p in all_paths:
if p.startswith(folder_prefix):
remainder = p[len(folder_prefix) :]
if "/" in remainder:
folders.add(remainder.split("/", 1)[0])
else:
files.add(remainder)
lines: list[str] = [] lines: list[str] = []
# Breadcrumb # Breadcrumb
@ -729,63 +753,40 @@ def _render_folder_index_html(
lines.append(f'<a href="{root_path}/navigate/{accumulated}">{part}</a>') lines.append(f'<a href="{root_path}/navigate/{accumulated}">{part}</a>')
lines.append("</nav>") lines.append("</nav>")
def _render_folder(folder_prefix: str, depth: int = 0) -> list[str]: href_params = ""
"""Recursively render a folder's contents.""" if current_order is not None and current_delay is not None:
result: list[str] = [] href_params = f"?order={current_order}&delay={current_delay}"
indent = "&nbsp;&nbsp;" * depth
prefix = folder_prefix or ""
folders: set[str] = set() for folder in sorted(folders):
files: set[str] = set() folder_path = f"{folder_prefix}{folder}/" if folder_prefix else f"{folder}/"
for p in all_paths: lines.append(
if p.startswith(prefix): f'<div class="index-item folder">'
remainder = p[len(prefix) :] f'<a href="{root_path}/navigate/{folder_path}">📁 {folder}</a>'
if "/" in remainder: f"</div>"
folders.add(remainder.split("/", 1)[0]) )
else:
files.add(remainder)
for folder in sorted(folders): for file in sorted(files):
folder_path = f"{prefix}{folder}/" if prefix else f"{folder}/" file_path = f"{folder_prefix}{file}" if folder_prefix else file
result.append( is_current = file_path == current_path
f'<div class="index-item folder">' cls = "index-item file current" if is_current else "index-item file"
f'{indent}<a href="{root_path}/navigate/{folder_path}">📁 {folder}</a>' lines.append(
f"</div>" f'<div class="{cls}">'
) f'<a href="{root_path}/navigate/{file_path}{href_params}">📄 {file}</a>'
result.extend(_render_folder(folder_path, depth + 1)) f"</div>"
)
for file in sorted(files):
file_path = f"{prefix}{file}" if prefix else file
is_current = file_path == current_path
cls = "index-item file current" if is_current else "index-item file"
href_params = ""
if current_order is not None and current_delay is not None:
href_params = f"?order={current_order}&delay={current_delay}"
result.append(
f'<div class="{cls}">'
f'{indent}<a href="{root_path}/navigate/{file_path}{href_params}">📄 {file}</a>'
f"</div>"
)
return result
lines.extend(_render_folder(""))
return "\n".join(lines) return "\n".join(lines)
def _render_folder_index_page( def _render_folder_index_page(
path: str, path: str,
folders: list[str],
files: list[str],
current_order: str | None = None, current_order: str | None = None,
current_delay: int | None = None, current_delay: int | None = None,
) -> HTMLResponse: ) -> HTMLResponse:
"""Render a folder index page showing subfolders and files. """Render a folder index page showing the current folder's contents.
Args: Args:
path: The folder path (e.g., 'folder/'). path: The folder path (e.g., 'folder/').
folders: List of subfolder names.
files: List of file names.
current_order: Current navigation order. current_order: Current navigation order.
current_delay: Current navigation delay. current_delay: Current navigation delay.
@ -797,8 +798,10 @@ def _render_folder_index_page(
template = string.Template(content) template = string.Template(content)
# Build folder index sidebar HTML using recursive tree renderer # Build folder index sidebar HTML showing current folder contents
folder_path = path.rstrip("/") or None folder_path = path.rstrip("/")
if folder_path:
folder_path += "/"
folder_index_html = _render_folder_index_html( folder_index_html = _render_folder_index_html(
current_path=folder_path, current_path=folder_path,
current_order=current_order, current_order=current_order,
@ -856,8 +859,6 @@ async def navigate_page(
raise HTTPException(status_code=404, detail="File not found") raise HTTPException(status_code=404, detail="File not found")
return _render_folder_index_page( return _render_folder_index_page(
path if path else "/", path if path else "/",
folders,
files,
current_order=order, current_order=order,
current_delay=delay, current_delay=delay,
) )

View File

@ -115,14 +115,17 @@ class TestNavigatePage:
assert "/navigate/folder/deep.txt" in response.text assert "/navigate/folder/deep.txt" in response.text
assert "/navigate/folder/image.png" in response.text assert "/navigate/folder/image.png" in response.text
async def test_subfolder_index_shows_full_tree( async def test_subfolder_index_shows_only_current_folder(
self, client_zip_navigate: AsyncClient self, client_zip_navigate: AsyncClient
) -> None: ) -> None:
"""Subfolder index sidebar shows full tree from root.""" """Subfolder index shows only that folder's contents, not the full tree."""
response = await client_zip_navigate.get("/navigate/folder/") response = await client_zip_navigate.get("/navigate/folder/")
assert response.status_code == 200 assert response.status_code == 200
# Should still show root-level items in the tree # Should show folder's own files
assert "/navigate/top.txt" in response.text assert "/navigate/folder/deep.txt" in response.text
assert "/navigate/folder/image.png" in response.text
# Should NOT show root-level items
assert "/navigate/top.txt" not in response.text
async def test_file_page_has_sidebar( async def test_file_page_has_sidebar(
self, client_zip_navigate: AsyncClient self, client_zip_navigate: AsyncClient