docs: Added package manager tab group synchronization across the entire installation page (#2421)
Co-authored-by: Patryk Kuniczak <p.kuniczak@gmail.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import BlogLayout from '../components/BlogLayout.vue';
|
||||
import './custom.css';
|
||||
import 'virtual:group-icons.css';
|
||||
import type { EnhanceAppContext } from 'vitepress/client';
|
||||
import { setupCodeGroupSync } from '../utils/code-groups-sync';
|
||||
|
||||
export default {
|
||||
extends: DefaultTheme,
|
||||
@@ -17,5 +18,7 @@ export default {
|
||||
.component('UsingWxtSection', UsingWxtSection)
|
||||
.component('ExampleSearch', ExampleSearch)
|
||||
.component('blog', BlogLayout);
|
||||
|
||||
setupCodeGroupSync();
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
const CODE_GROUP_SELECTORS = {
|
||||
root: '.vp-code-group',
|
||||
input: '.vp-code-group .tabs input',
|
||||
label: '.tabs label',
|
||||
} as const;
|
||||
|
||||
function getTabTitle(label: HTMLLabelElement) {
|
||||
return label.dataset.title?.trim() || label.textContent?.trim();
|
||||
}
|
||||
|
||||
function getCodeGroupTitle(input: HTMLInputElement) {
|
||||
const label = input.parentElement?.querySelector<HTMLLabelElement>(
|
||||
`label[for="${input.id}"]`,
|
||||
);
|
||||
|
||||
return label ? getTabTitle(label) : undefined;
|
||||
}
|
||||
|
||||
function findCodeGroupTabIndex(group: HTMLElement, title: string) {
|
||||
return Array.from(
|
||||
group.querySelectorAll<HTMLLabelElement>(CODE_GROUP_SELECTORS.label),
|
||||
).findIndex((label) => getTabTitle(label) === title);
|
||||
}
|
||||
|
||||
function syncCodeGroupSelection(group: HTMLElement, title: string) {
|
||||
const targetIndex = findCodeGroupTabIndex(group, title);
|
||||
|
||||
if (targetIndex < 0) return;
|
||||
|
||||
const blocks = group.querySelector('.blocks');
|
||||
const targetBlock = blocks?.children[targetIndex];
|
||||
if (!blocks || !targetBlock || targetBlock.classList.contains('active'))
|
||||
return;
|
||||
|
||||
blocks.querySelector('.active')?.classList.remove('active');
|
||||
targetBlock.classList.add('active');
|
||||
|
||||
const input = group.querySelectorAll<HTMLInputElement>(
|
||||
CODE_GROUP_SELECTORS.input,
|
||||
)[targetIndex];
|
||||
if (input) input.checked = true;
|
||||
}
|
||||
|
||||
function syncCodeGroupTabs(event: Event) {
|
||||
const target = event.target;
|
||||
if (
|
||||
!(target instanceof HTMLInputElement) ||
|
||||
!target.matches(CODE_GROUP_SELECTORS.input)
|
||||
)
|
||||
return;
|
||||
|
||||
const activeGroup = target.closest(CODE_GROUP_SELECTORS.root);
|
||||
const activeTitle = getCodeGroupTitle(target);
|
||||
if (!activeTitle) return;
|
||||
|
||||
document
|
||||
.querySelectorAll<HTMLElement>(CODE_GROUP_SELECTORS.root)
|
||||
.forEach((group) => {
|
||||
if (group === activeGroup) return;
|
||||
|
||||
syncCodeGroupSelection(group, activeTitle);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps every code group on the page in sync: selecting a package manager (or
|
||||
* any tab) in one group switches the matching tab in all the other groups.
|
||||
*/
|
||||
export function setupCodeGroupSync() {
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
window.addEventListener('change', syncCodeGroupTabs, true);
|
||||
}
|
||||
Reference in New Issue
Block a user