ADD new frontend

This commit is contained in:
Urtzi Alfaro
2025-08-28 10:41:04 +02:00
parent 9c247a5f99
commit 0fd273cfce
492 changed files with 114979 additions and 1632 deletions

View File

@@ -0,0 +1,200 @@
import React, { forwardRef } from 'react';
import { clsx } from 'clsx';
import { useTheme } from '../../../contexts/ThemeContext';
import { PublicHeader } from '../PublicHeader';
import { Footer } from '../Footer';
export interface PublicLayoutProps {
children: React.ReactNode;
className?: string;
/**
* Control header visibility
*/
showHeader?: boolean;
/**
* Control footer visibility
*/
showFooter?: boolean;
/**
* Header configuration
*/
headerProps?: {
showThemeToggle?: boolean;
showAuthButtons?: boolean;
navigationItems?: Array<{
id: string;
label: string;
href: string;
external?: boolean;
}>;
variant?: 'default' | 'transparent' | 'minimal';
logo?: React.ReactNode;
};
/**
* Footer configuration
*/
footerProps?: {
compact?: boolean;
showPrivacyLinks?: boolean;
showThemeToggle?: boolean;
showVersion?: boolean;
};
/**
* Layout variant
*/
variant?: 'default' | 'centered' | 'full-width';
/**
* Add minimum height to content area
*/
minHeight?: 'screen' | 'content' | 'none';
/**
* Content container max width
*/
maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '7xl' | 'full' | 'none';
/**
* Content padding
*/
contentPadding?: 'none' | 'sm' | 'md' | 'lg';
}
export interface PublicLayoutRef {
scrollToTop: () => void;
scrollToBottom: () => void;
}
/**
* PublicLayout - Layout wrapper for public pages (landing, login, register)
*
* Features:
* - Modular header and footer with configurable props
* - Multiple layout variants for different page types
* - Responsive design with flexible content areas
* - Theme integration and consistent styling
* - Accessible structure with proper landmarks
* - Scroll utilities for navigation
*/
export const PublicLayout = forwardRef<PublicLayoutRef, PublicLayoutProps>(({
children,
className,
showHeader = true,
showFooter = true,
headerProps = {},
footerProps = {},
variant = 'default',
minHeight = 'screen',
maxWidth = '7xl',
contentPadding = 'md',
}, ref) => {
const { resolvedTheme } = useTheme();
const layoutRef = React.useRef<HTMLDivElement>(null);
// Scroll utilities
const scrollToTop = React.useCallback(() => {
layoutRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
}, []);
const scrollToBottom = React.useCallback(() => {
layoutRef.current?.scrollIntoView({ behavior: 'smooth', block: 'end' });
}, []);
// Expose ref methods
React.useImperativeHandle(ref, () => ({
scrollToTop,
scrollToBottom,
}), [scrollToTop, scrollToBottom]);
// Max width classes
const maxWidthClasses = {
sm: 'max-w-sm',
md: 'max-w-md',
lg: 'max-w-lg',
xl: 'max-w-xl',
'2xl': 'max-w-2xl',
'7xl': 'max-w-7xl',
full: 'max-w-full',
none: '',
};
// Content padding classes
const paddingClasses = {
none: '',
sm: 'px-4 py-6',
md: 'px-4 py-8 sm:px-6 lg:px-8',
lg: 'px-4 py-12 sm:px-6 lg:px-8 lg:py-16',
};
// Min height classes
const minHeightClasses = {
screen: 'min-h-screen',
content: 'min-h-[50vh]',
none: '',
};
return (
<div
ref={layoutRef}
className={clsx(
'flex flex-col',
minHeightClasses[minHeight],
'bg-[var(--bg-primary)]',
resolvedTheme,
className
)}
data-testid="public-layout"
>
{/* Header */}
{showHeader && (
<PublicHeader
showThemeToggle={true}
showAuthButtons={true}
variant="default"
{...headerProps}
/>
)}
{/* Main content */}
<main
role="main"
className={clsx(
'flex-1 flex flex-col',
variant === 'centered' && 'items-center justify-center',
variant === 'full-width' && 'w-full',
variant === 'default' && 'w-full'
)}
aria-label="Contenido principal"
>
{variant === 'centered' ? (
// Centered variant - useful for login/register pages
<div className={clsx(
'w-full mx-auto flex flex-col',
maxWidthClasses[maxWidth],
paddingClasses[contentPadding]
)}>
{children}
</div>
) : (
// Default and full-width variants
<div className={clsx(
variant === 'default' && maxWidthClasses[maxWidth] && `mx-auto w-full ${maxWidthClasses[maxWidth]}`,
paddingClasses[contentPadding]
)}>
{children}
</div>
)}
</main>
{/* Footer */}
{showFooter && (
<Footer
compact={false}
showPrivacyLinks={true}
showThemeToggle={false} // Header already has theme toggle
showVersion={true}
{...footerProps}
/>
)}
</div>
);
});
PublicLayout.displayName = 'PublicLayout';

View File

@@ -0,0 +1 @@
export { PublicLayout, type PublicLayoutProps, type PublicLayoutRef } from './PublicLayout';