Fix navigation to not display the whole structure, just the current root.
This commit is contained in:
parent
b8947af2db
commit
eaf574231c
@ -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
97
main.py
@ -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 = " " * 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,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user