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;
}
.play-btn:hover { color: rgba(255, 255, 255, 1); transform: scale(1.1); }
/q .hidden { display: none; }
.hidden { display: none; }
#sidebar {
position: fixed;
top: 0;
@ -72,6 +72,7 @@
display: block;
padding: 4px 8px;
border-radius: 4px;
text-wrap-mode: nowrap;
}
#sidebar a:hover {
background: #3a3a3a;
@ -185,6 +186,7 @@
}
} else if (e.key.toLowerCase() === 'i') {
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_delay: int | None = None,
) -> 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:
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.
"""
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] = []
# Breadcrumb
@ -729,63 +753,40 @@ def _render_folder_index_html(
lines.append(f'<a href="{root_path}/navigate/{accumulated}">{part}</a>')
lines.append("</nav>")
def _render_folder(folder_prefix: str, depth: int = 0) -> list[str]:
"""Recursively render a folder's contents."""
result: list[str] = []
indent = "&nbsp;&nbsp;" * depth
prefix = folder_prefix or ""
href_params = ""
if current_order is not None and current_delay is not None:
href_params = f"?order={current_order}&delay={current_delay}"
folders: set[str] = set()
files: set[str] = set()
for p in all_paths:
if p.startswith(prefix):
remainder = p[len(prefix) :]
if "/" in remainder:
folders.add(remainder.split("/", 1)[0])
else:
files.add(remainder)
for folder in sorted(folders):
folder_path = f"{folder_prefix}{folder}/" if folder_prefix else f"{folder}/"
lines.append(
f'<div class="index-item folder">'
f'<a href="{root_path}/navigate/{folder_path}">📁 {folder}</a>'
f"</div>"
)
for folder in sorted(folders):
folder_path = f"{prefix}{folder}/" if prefix else f"{folder}/"
result.append(
f'<div class="index-item folder">'
f'{indent}<a href="{root_path}/navigate/{folder_path}">📁 {folder}</a>'
f"</div>"
)
result.extend(_render_folder(folder_path, depth + 1))
for file in sorted(files):
file_path = f"{folder_prefix}{file}" if folder_prefix else file
is_current = file_path == current_path
cls = "index-item file current" if is_current else "index-item file"
lines.append(
f'<div class="{cls}">'
f'<a href="{root_path}/navigate/{file_path}{href_params}">📄 {file}</a>'
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)
def _render_folder_index_page(
path: str,
folders: list[str],
files: list[str],
current_order: str | None = None,
current_delay: int | None = None,
) -> HTMLResponse:
"""Render a folder index page showing subfolders and files.
"""Render a folder index page showing the current folder's contents.
Args:
path: The folder path (e.g., 'folder/').
folders: List of subfolder names.
files: List of file names.
current_order: Current navigation order.
current_delay: Current navigation delay.
@ -797,8 +798,10 @@ def _render_folder_index_page(
template = string.Template(content)
# Build folder index sidebar HTML using recursive tree renderer
folder_path = path.rstrip("/") or None
# Build folder index sidebar HTML showing current folder contents
folder_path = path.rstrip("/")
if folder_path:
folder_path += "/"
folder_index_html = _render_folder_index_html(
current_path=folder_path,
current_order=current_order,
@ -856,8 +859,6 @@ async def navigate_page(
raise HTTPException(status_code=404, detail="File not found")
return _render_folder_index_page(
path if path else "/",
folders,
files,
current_order=order,
current_delay=delay,
)

View File

@ -115,14 +115,17 @@ class TestNavigatePage:
assert "/navigate/folder/deep.txt" 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
) -> 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/")
assert response.status_code == 200
# Should still show root-level items in the tree
assert "/navigate/top.txt" in response.text
# Should show folder's own files
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(
self, client_zip_navigate: AsyncClient