create for series

This commit is contained in:
Nicolas Cantu 2026-01-13 23:46:43 +01:00
parent 8f3f62f7bf
commit 57acb3d9f3
3 changed files with 77 additions and 37 deletions

View File

@ -12,7 +12,7 @@ interface CardProps {
function getVariantClasses(variant: CardVariant, hasOnClick: boolean): string { function getVariantClasses(variant: CardVariant, hasOnClick: boolean): string {
const baseClasses = 'border rounded-lg bg-cyber-dark' const baseClasses = 'border rounded-lg bg-cyber-dark'
switch (variant) { switch (variant) {
case 'default': case 'default':
return `${baseClasses} border-neon-cyan/30` return `${baseClasses} border-neon-cyan/30`

View File

@ -62,44 +62,84 @@ export function MobileMenu({ children, 'aria-label': ariaLabel }: MobileMenuProp
return ( return (
<> <>
<button <MobileMenuButton
isOpen={isOpen}
onClick={() => setIsOpen(!isOpen)} onClick={() => setIsOpen(!isOpen)}
className="md:hidden text-cyber-accent hover:text-neon-cyan transition-colors focus:outline-none focus:ring-2 focus:ring-neon-cyan rounded p-2" ariaLabel={ariaLabel ?? 'Toggle menu'}
aria-label={ariaLabel ?? 'Toggle menu'} />
aria-expanded={isOpen}
aria-controls="mobile-menu"
>
<HamburgerIcon isOpen={isOpen} />
</button>
{isOpen && ( {isOpen && (
<> <MobileMenuDrawer
<div isOpen={isOpen}
className="fixed inset-0 bg-black bg-opacity-50 z-40 md:hidden" onClose={() => setIsOpen(false)}
onClick={() => setIsOpen(false)} ariaLabel={ariaLabel ?? 'Mobile menu'}
aria-hidden="true" >
/> {children}
<div </MobileMenuDrawer>
id="mobile-menu"
className="fixed top-0 right-0 h-full w-80 max-w-[85vw] bg-cyber-dark border-l border-neon-cyan/30 shadow-glow-cyan z-50 transform transition-transform md:hidden overflow-y-auto"
role="dialog"
aria-modal="true"
aria-label={ariaLabel ?? 'Mobile menu'}
>
<div className="p-4">
<div className="flex justify-end mb-4">
<button
onClick={() => setIsOpen(false)}
className="text-cyber-accent hover:text-neon-cyan text-2xl transition-colors focus:outline-none focus:ring-2 focus:ring-neon-cyan rounded"
aria-label="Close menu"
>
×
</button>
</div>
<div className="space-y-4">{children}</div>
</div>
</div>
</>
)} )}
</> </>
) )
} }
function MobileMenuButton({
isOpen,
onClick,
ariaLabel,
}: {
isOpen: boolean
onClick: () => void
ariaLabel: string
}): React.ReactElement {
return (
<button
onClick={onClick}
className="md:hidden text-cyber-accent hover:text-neon-cyan transition-colors focus:outline-none focus:ring-2 focus:ring-neon-cyan rounded p-2"
aria-label={ariaLabel}
aria-expanded={isOpen}
aria-controls="mobile-menu"
>
<HamburgerIcon isOpen={isOpen} />
</button>
)
}
function MobileMenuDrawer({
isOpen,
onClose,
ariaLabel,
children,
}: {
isOpen: boolean
onClose: () => void
ariaLabel: string
children: ReactNode
}): React.ReactElement {
return (
<>
<div
className="fixed inset-0 bg-black bg-opacity-50 z-40 md:hidden"
onClick={onClose}
aria-hidden="true"
/>
<div
id="mobile-menu"
className="fixed top-0 right-0 h-full w-80 max-w-[85vw] bg-cyber-dark border-l border-neon-cyan/30 shadow-glow-cyan z-50 transform transition-transform md:hidden overflow-y-auto"
role="dialog"
aria-modal="true"
aria-label={ariaLabel}
>
<div className="p-4">
<div className="flex justify-end mb-4">
<button
onClick={onClose}
className="text-cyber-accent hover:text-neon-cyan text-2xl transition-colors focus:outline-none focus:ring-2 focus:ring-neon-cyan rounded"
aria-label="Close menu"
>
×
</button>
</div>
<div className="space-y-4">{children}</div>
</div>
</div>
</>
)
}

View File

@ -26,7 +26,7 @@ export function Skeleton({
const variantClasses = getVariantClasses(variant) const variantClasses = getVariantClasses(variant)
const baseClasses = 'bg-cyber-light animate-pulse' const baseClasses = 'bg-cyber-light animate-pulse'
const style: React.CSSProperties = {} const style: React.CSSProperties = {}
if (width) { if (width) {
style.width = typeof width === 'number' ? `${width}px` : width style.width = typeof width === 'number' ? `${width}px` : width
} }