mirror of
https://github.com/zoriya/v10.git
synced 2026-08-09 15:46:42 +00:00
144 lines
5.1 KiB
TypeScript
144 lines
5.1 KiB
TypeScript
import type { AnySupportedStyle, SupportedFramework } from '@/types/docs';
|
|
|
|
import { navigate } from 'astro:transitions/client';
|
|
|
|
import { getAvailableStyles, getDefaultStyle, SUPPORTED_FRAMEWORKS } from '@/types/docs';
|
|
import { findFirstGuide, findGuideBySlug, getValidStylesForGuide } from '@/utils/docs/sidebar';
|
|
|
|
interface SelectorProps {
|
|
currentFramework: SupportedFramework;
|
|
currentStyle: AnySupportedStyle;
|
|
}
|
|
|
|
/**
|
|
* Extract the current guide slug from the docs URL.
|
|
* URL format: /docs/framework/{framework}/style/{style}/{slug}/
|
|
* @returns The guide slug (everything after the style parameter)
|
|
*/
|
|
function getCurrentGuideSlug(): string {
|
|
const pathParts = window.location.pathname.split('/').filter(Boolean);
|
|
const styleIndex = pathParts.indexOf('style');
|
|
const slugParts = pathParts.slice(styleIndex + 2); // Everything after the style value
|
|
return slugParts.join('/');
|
|
}
|
|
|
|
export function Selectors({ currentFramework, currentStyle }: SelectorProps) {
|
|
const handleFrameworkChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
|
const newFramework = event.target.value as SupportedFramework;
|
|
|
|
// Get current guide slug from URL
|
|
const currentGuideSlug = getCurrentGuideSlug();
|
|
|
|
// Find the current guide in the sidebar
|
|
const currentGuide = findGuideBySlug(currentGuideSlug);
|
|
|
|
if (!currentGuide) {
|
|
// No current guide found, redirect to first guide of new framework
|
|
const firstGuide = findFirstGuide(newFramework, getDefaultStyle(newFramework));
|
|
if (firstGuide) {
|
|
navigate(`/docs/framework/${newFramework}/style/${getDefaultStyle(newFramework)}/${firstGuide}/`);
|
|
} else {
|
|
navigate('/docs/');
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Check if guide is available for the new framework
|
|
if (currentGuide.frameworks && !currentGuide.frameworks.includes(newFramework)) {
|
|
// Guide not available in new framework, redirect to first guide
|
|
const firstGuide = findFirstGuide(newFramework, getDefaultStyle(newFramework));
|
|
if (firstGuide) {
|
|
navigate(`/docs/framework/${newFramework}/style/${getDefaultStyle(newFramework)}/${firstGuide}/`);
|
|
} else {
|
|
navigate('/docs/');
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Get valid styles for this guide in the new framework
|
|
const validStyles = getValidStylesForGuide(currentGuide, newFramework);
|
|
|
|
if (validStyles.length === 0) {
|
|
// Guide not available in new framework, go to first guide
|
|
const firstGuide = findFirstGuide(newFramework, getDefaultStyle(newFramework));
|
|
if (firstGuide) {
|
|
navigate(`/docs/framework/${newFramework}/style/${getDefaultStyle(newFramework)}/${firstGuide}/`);
|
|
} else {
|
|
navigate('/docs/');
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Pick best style: current if still valid, otherwise first valid
|
|
const newStyle = validStyles.includes(currentStyle) ? currentStyle : validStyles[0];
|
|
|
|
// Navigate to same guide with adjusted framework/style
|
|
navigate(`/docs/framework/${newFramework}/style/${newStyle}/${currentGuideSlug}/`);
|
|
};
|
|
|
|
const handleStyleChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
|
const newStyle = event.target.value as AnySupportedStyle;
|
|
|
|
// Get current guide slug from URL
|
|
const currentGuideSlug = getCurrentGuideSlug();
|
|
|
|
// Find the current guide in the sidebar
|
|
const currentGuide = findGuideBySlug(currentGuideSlug);
|
|
|
|
if (!currentGuide) {
|
|
// No current guide found, redirect to first guide of new style
|
|
const firstGuide = findFirstGuide(currentFramework, newStyle);
|
|
if (firstGuide) {
|
|
navigate(`/docs/framework/${currentFramework}/style/${newStyle}/${firstGuide}/`);
|
|
} else {
|
|
navigate('/docs/');
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Check if guide is valid for current framework and new style
|
|
const validStyles = getValidStylesForGuide(currentGuide, currentFramework);
|
|
|
|
if (!validStyles.includes(newStyle)) {
|
|
// Guide not available for new style, go to first guide
|
|
const firstGuide = findFirstGuide(currentFramework, newStyle);
|
|
if (firstGuide) {
|
|
navigate(`/docs/framework/${currentFramework}/style/${newStyle}/${firstGuide}/`);
|
|
} else {
|
|
navigate('/docs/');
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Guide supports the new style, navigate to it
|
|
navigate(`/docs/framework/${currentFramework}/style/${newStyle}/${currentGuideSlug}/`);
|
|
};
|
|
|
|
const availableStyles = getAvailableStyles(currentFramework);
|
|
|
|
return (
|
|
<div className="mb-4">
|
|
<div>
|
|
<label htmlFor="framework-select">Framework:</label>
|
|
<select id="framework-select" value={currentFramework} onChange={handleFrameworkChange}>
|
|
{SUPPORTED_FRAMEWORKS.map(fw => (
|
|
<option key={fw} value={fw}>
|
|
{fw}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label htmlFor="style-select">Style:</label>
|
|
<select id="style-select" value={currentStyle} onChange={handleStyleChange}>
|
|
{availableStyles.map(st => (
|
|
<option key={st} value={st}>
|
|
{st}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|