Use /search/:term path-based search routing

This commit is contained in:
2026-05-27 21:15:58 +00:00
parent 29cda926a2
commit 02a89aee68
2 changed files with 59 additions and 23 deletions
+54 -23
View File
@@ -212,11 +212,20 @@ function normalizeSearchQuery(value: unknown): string {
} }
function getRouteSearchQuery() { function getRouteSearchQuery() {
return normalizeSearchQuery(route.query.q) if (route.name !== "search") {
return ""
}
return normalizeSearchQuery(route.params.term)
}
function getSearchPath(term: string) {
return router.resolve({ name: "search", params: { term } }).path
} }
function getBrowsePath() { function getBrowsePath() {
return route.meta.view === "series" ? "/series" : "/movies" if (route.meta.view === "series") return "/series"
if (route.meta.view === "movies") return "/movies"
return searchReturnPath.value ?? "/movies"
} }
function getBrowseViewFromPath(path: string): "movies" | "series" { function getBrowseViewFromPath(path: string): "movies" | "series" {
@@ -445,6 +454,28 @@ function getSearchExitTargetFromFocusedCard(): { path: "/movies" | "/series"; it
return null return null
} }
function getDetailSearchPath(): string | null {
if (!route.params.id) return null
const stateSearchPathRaw = window.history.state?.searchPath
if (typeof stateSearchPathRaw === "string") {
const stateSearchPath = normalizeHistoryPath(stateSearchPathRaw)
if (stateSearchPath.startsWith("/search/")) {
return stateSearchPath
}
}
const backPath =
typeof window.history.state?.back === "string"
? normalizeHistoryPath(window.history.state.back)
: ""
if (backPath.startsWith("/search/")) {
return backPath
}
return null
}
function clearSearch(options: { preferBack?: boolean; targetPath?: string } = {}) { function clearSearch(options: { preferBack?: boolean; targetPath?: string } = {}) {
const currentQuery = getRouteSearchQuery() const currentQuery = getRouteSearchQuery()
const targetPath = options.targetPath ?? getBrowsePath() const targetPath = options.targetPath ?? getBrowsePath()
@@ -498,11 +529,11 @@ function updateSearchQuery(nextValue: string) {
saveFocusForPage(currentView.value) saveFocusForPage(currentView.value)
} }
searchReturnPath.value = browsePath searchReturnPath.value = browsePath
void router.push({ path: browsePath, query: { q: nextQuery } }) void router.push(getSearchPath(nextQuery))
return return
} }
void router.replace({ path: browsePath, query: { q: nextQuery } }) void router.replace(getSearchPath(nextQuery))
} }
// Handle Escape key for navigation hierarchy // Handle Escape key for navigation hierarchy
@@ -516,13 +547,13 @@ function handleEscapeKey(event: KeyboardEvent) {
} }
const path = route.path const path = route.path
const activeSearchQuery = getRouteSearchQuery() const detailSearchPath = getDetailSearchPath()
if (route.params.id && activeSearchQuery) { if (route.params.id && detailSearchPath) {
event.preventDefault() event.preventDefault()
const targetPath = getBrowsePath() void router.push(detailSearchPath).finally(() => {
router.push({ path: targetPath, query: { q: activeSearchQuery } }) restoreFocusForPage("movies")
restoreFocusForPage(getBrowseViewFromPath(targetPath)) })
return return
} }
@@ -582,12 +613,12 @@ onUnmounted(() => {
// Handle back navigation (Escape key or Back button) // Handle back navigation (Escape key or Back button)
function goBack() { function goBack() {
const path = route.path const path = route.path
const activeSearchQuery = getRouteSearchQuery() const detailSearchPath = getDetailSearchPath()
if (route.params.id && activeSearchQuery) { if (route.params.id && detailSearchPath) {
const targetPath = getBrowsePath() void router.push(detailSearchPath).finally(() => {
router.push({ path: targetPath, query: { q: activeSearchQuery } }) restoreFocusForPage("movies")
restoreFocusForPage(getBrowseViewFromPath(targetPath)) })
return return
} }
@@ -615,7 +646,7 @@ const currentView = computed(() => {
}) })
const headerCurrentView = computed<"movies" | "series" | "search">(() => { const headerCurrentView = computed<"movies" | "series" | "search">(() => {
return selectedItem.value && searchQuery.value ? "search" : currentView.value return selectedItem.value && getDetailSearchPath() ? "search" : currentView.value
}) })
// Header position based on current page // Header position based on current page
@@ -688,21 +719,21 @@ function showDetail(item: MediaItem) {
if (playableFile) { if (playableFile) {
handlePlay(playableFile) handlePlay(playableFile)
} else { } else {
const query = searchQuery.value ? { q: searchQuery.value } : undefined const searchPath = searchQuery.value ? getSearchPath(searchQuery.value) : null
router.push({ path: `/series/${epData.series.id}`, query }) router.push({ path: `/series/${epData.series.id}`, state: searchPath ? { searchPath } : undefined })
} }
} else { } else {
const query = searchQuery.value ? { q: searchQuery.value } : undefined const searchPath = searchQuery.value ? getSearchPath(searchQuery.value) : null
router.push({ path: `/${item.type}/${item.id}`, query }) router.push({ path: `/${item.type}/${item.id}`, state: searchPath ? { searchPath } : undefined })
} }
} }
// Close detail by navigating back to list // Close detail by navigating back to list
function closeDetail() { function closeDetail() {
const activeSearchQuery = getRouteSearchQuery() const detailSearchPath = getDetailSearchPath()
const targetPath = getBrowsePath() const targetPath = getBrowsePath()
if (activeSearchQuery) { if (detailSearchPath) {
router.push({ path: targetPath, query: { q: activeSearchQuery } }) router.push(detailSearchPath)
} else { } else {
router.push(targetPath) router.push(targetPath)
} }
@@ -1046,7 +1077,7 @@ watch(
if (nextQuery !== searchQuery.value) { if (nextQuery !== searchQuery.value) {
searchQuery.value = nextQuery searchQuery.value = nextQuery
} }
if (!nextQuery) { if (!nextQuery && route.name !== "search") {
searchReturnPath.value = null searchReturnPath.value = null
} }
}, },
+5
View File
@@ -31,6 +31,11 @@ const router = createRouter({
component: EmptyRouteComponent, component: EmptyRouteComponent,
meta: { view: "movies" }, meta: { view: "movies" },
}, },
{
path: "/search/:term",
name: "search",
component: EmptyRouteComponent,
},
{ {
path: "/series", path: "/series",
name: "series", name: "series",