diff --git a/viewer/directory.py b/viewer/directory.py
index b1b34eb..e13f02c 100644
--- a/viewer/directory.py
+++ b/viewer/directory.py
@@ -169,6 +169,9 @@ def render_directory(request, path_text, full_path):
"search_action_url": gallery_url(
Path(path_text) if path_text != "" else None, True, search_action_query
),
+ "clear_search_url": gallery_url(
+ Path(path_text) if path_text != "" else None, True, None
+ ),
}
# sort_label depends on SORT_LABELS in common; import lazily to avoid circulars
diff --git a/viewer/templates/gallery_view.html b/viewer/templates/gallery_view.html
index e8186df..090152e 100644
--- a/viewer/templates/gallery_view.html
+++ b/viewer/templates/gallery_view.html
@@ -33,6 +33,11 @@
diff --git a/viewer/test.py b/viewer/test.py
index 583cb40..55d2ef3 100644
--- a/viewer/test.py
+++ b/viewer/test.py
@@ -235,6 +235,26 @@ class GalleryViewTests(GalleryBaseTests):
self.assertIn("sort=recent", url)
self.assertIn("theme=light", url)
+ def test_clear_search_url_present_and_clears_query(self):
+ # When a search is active the context should provide a URL that
+ # clears the search (no query parameters) for the current path.
+ response = self.client.get("/gallery/?search=match&sort=recent&theme=light")
+ self.assertEqual(response.status_code, 200)
+
+ clear_url = response.context.get("clear_search_url")
+ # For the root path the clear URL should be the gallery root without query
+ self.assertEqual(clear_url, "/gallery/")
+
+ def test_clear_search_url_uses_nested_path(self):
+ # Ensure clear_search_url respects nested paths (clears search but preserves path)
+ response = self.client.get(
+ "/gallery/sub_a/?search=match&sort=recent&theme=light"
+ )
+ self.assertEqual(response.status_code, 200)
+
+ clear_url = response.context.get("clear_search_url")
+ self.assertTrue(clear_url.find("/gallery/sub_a/") == 0)
+
def test_search_action_url_uses_nested_path(self):
response = self.client.get("/gallery/sub_a/?sort=recent&theme=light")
self.assertEqual(response.status_code, 200)
@@ -445,6 +465,17 @@ class GalleryTemplateTests(GalleryBaseTests):
self.assertIn("Most visited", body)
self.assertIn("Recently visited", body)
+ def test_clear_search_button_shown_when_searching(self):
+ # The template should render a clear-search button when a search is active
+ resp = self.client.get("/gallery/?search=match")
+ body = resp.content.decode("utf-8")
+ self.assertIn('aria-label="Clear search"', body)
+
+ # And it should not be present when there's no search
+ resp2 = self.client.get("/gallery/")
+ body2 = resp2.content.decode("utf-8")
+ self.assertNotIn('aria-label="Clear search"', body2)
+
def test_template_shows_fallback_icon_for_empty_subdir(self):
response = self.client.get("/gallery/")
self.assertEqual(response.status_code, 200)