Files
1da4059d59 fix(docs): sync URL params with UI state on categories page (#4111)
* fix(docs): sync URL params with UI state on category and search interactions

Search, category selection, and the icon detail drawer each modified the
URL independently, causing parameters to be silently dropped. Searching
didn't clear the category hash, clicking a category dropped the search
param, and closing the drawer hard-coded the path without preserving
either.

Consolidate URL construction so every navigation preserves both ?search=
and #category as appropriate. Split useCategoryView into a pure getter
and a sync variant (useCategoryViewSync) so event listeners and route
watchers are registered once in CategoryList.vue instead of in every
consumer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(docs): disable click on inactive categories during search

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Update docs/.vitepress/theme/components/icons/IconsCategoryOverview.vue

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>

* Update docs/.vitepress/theme/components/icons/IconsOverview.vue

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>

* refactor(docs): use URL constructor in CategoryListItem

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-04-28 20:38:59 +02:00

67 lines
1.7 KiB
TypeScript

import { useRoute } from 'vitepress';
import { ref, inject, Ref, onMounted, onUnmounted, watch } from 'vue';
export const CATEGORY_VIEW_CONTEXT = Symbol('categoryView');
interface CategoryViewContext {
selectedCategory: Ref<string>;
categoryCounts: Ref<Record<string, number>>;
}
export const categoryViewContext = {
selectedCategory: ref(),
categoryCounts: ref({}),
};
const CATEGORIES_PATH = '/icons/categories';
export function useCategoryView(): CategoryViewContext {
const context = inject<CategoryViewContext>(CATEGORY_VIEW_CONTEXT);
if (!context) {
throw new Error('useCategoryView must be used with categoryView context');
}
return context;
}
export function useCategoryViewSync(): CategoryViewContext {
const context = useCategoryView();
const route = useRoute();
function syncCategoryFromLocation() {
if (!window.location.pathname.startsWith(CATEGORIES_PATH)) {
context.selectedCategory.value = '';
context.categoryCounts.value = {};
return;
}
context.selectedCategory.value = window.location.hash
? decodeURIComponent(window.location.hash.slice(1))
: '';
}
onMounted(() => {
syncCategoryFromLocation();
window.addEventListener('hashchange', syncCategoryFromLocation);
window.addEventListener('popstate', syncCategoryFromLocation);
});
onUnmounted(() => {
window.removeEventListener('hashchange', syncCategoryFromLocation);
window.removeEventListener('popstate', syncCategoryFromLocation);
});
watch(route, (currentRoute) => {
if (currentRoute.path !== CATEGORIES_PATH) {
context.selectedCategory.value = '';
context.categoryCounts.value = {};
return;
}
syncCategoryFromLocation();
});
return context;
}