Files
v10/website/src/components/docs/Selectors.tsx
T

94 lines
2.8 KiB
TypeScript

import type { AnySupportedStyle, SupportedFramework, SupportedStyle } from '@/types/docs';
import { Select } from '@/components/Select';
import { FRAMEWORK_STYLES, isValidFramework, isValidStyleForFramework, SUPPORTED_FRAMEWORKS } from '@/types/docs';
import { resolveFrameworkChange, resolveStyleChange } from '@/utils/docs/routing';
interface SelectorProps<T extends SupportedFramework> {
currentFramework: T;
currentStyle: SupportedStyle<T>;
currentSlug: string;
}
export function Selectors({
currentFramework,
currentStyle,
currentSlug,
}: SelectorProps<SupportedFramework>) {
// TODO: use astro view transitions to preserve scroll position when switching from the same slug to the same slug
const handleFrameworkChange = (newFramework: SupportedFramework | null) => {
if (newFramework === null) return;
if (!isValidFramework(newFramework)) return;
const { url, shouldReplace } = resolveFrameworkChange({
currentFramework,
currentStyle,
currentSlug,
newFramework,
});
if (shouldReplace) {
// Maintaining the current slug, navigate without pushing onto the history stack
window.location.replace(url);
} else {
// Changing slug, use normal navigation
window.location.href = url;
}
};
const handleStyleChange = (newStyle: AnySupportedStyle | null) => {
if (newStyle === null) return;
if (!isValidStyleForFramework(currentFramework, newStyle)) return;
const { url, shouldReplace } = resolveStyleChange({
currentFramework,
currentStyle,
currentSlug,
newStyle,
});
if (shouldReplace) {
// Maintaining the current slug, navigate without pushing onto the history stack
window.location.replace(url);
} else {
// Changing slug, use normal navigation
window.location.href = url;
}
};
const availableStyles = FRAMEWORK_STYLES[currentFramework];
const frameworkOptions = SUPPORTED_FRAMEWORKS.map(fw => ({
value: fw,
label: fw,
}));
const styleOptions = availableStyles.map(st => ({
value: st,
label: st,
}));
return (
<div className="p-6 lg:py-2.5 xl:p-6 border-b border-light-40 dark:border-dark-80">
<div className="max-w-3xl mx-auto w-full grid gap-x-6 gap-y-2 items-center" style={{ gridTemplateColumns: 'auto minmax(0, 1fr)' }}>
<span>Framework</span>
<Select
value={currentFramework}
onChange={handleFrameworkChange}
options={frameworkOptions}
aria-label="Select framework"
data-testid="select-framework"
/>
<span>Style</span>
<Select
value={currentStyle}
onChange={handleStyleChange}
options={styleOptions}
aria-label="Select style"
data-testid="select-style"
/>
</div>
</div>
);
}