'use client'
import React from 'react'
import { cn } from '../../utils/cn'
import type { ActionsMenuGroup } from '../ui/actions-menu'
import { PageActions, type PageActionButton } from '../ui/page-actions'
import { BackButton } from './back-button'
// Legacy interface for backward compatibility (layout version)
interface LegacyPageContainerProps {
children: React.ReactNode;
className?: string;
/** Whether to apply full-width background to the entire section */
fullWidthBackground?: boolean;
/** Custom background style/className for the section wrapper */
backgroundClassName?: string;
/** Custom background style object */
backgroundStyle?: React.CSSProperties;
/** Custom padding for the content container (overrides default responsive padding) */
contentPadding?: string;
/** Custom max-width for the content container (default: max-w-[1920px]) */
maxWidth?: string;
/** HTML element type for the container */
as?: 'section' | 'div' | 'main' | 'article';
/** HTML id for the container */
id?: string;
}
// New advanced interface (UI version)
interface AdvancedPageContainerProps {
/**
* Page content
*/
children: React.ReactNode
/**
* Page variant determines layout structure
*/
variant?: 'list' | 'detail' | 'form' | 'content'
/**
* Page title (displayed as h1)
*/
title?: string
/**
* Subtitle or description (supports both string and ReactNode)
*/
subtitle?: string | React.ReactNode
/**
* Back button configuration
*/
backButton?: {
label?: string
onClick: () => void
}
/**
* Header actions (buttons, controls, etc.)
* Can be used together with or instead of `actions` prop
*/
headerActions?: React.ReactNode
/**
* Page action buttons configuration
* Automatically renders PageActions component with appropriate variant:
* - 'list' variant → 'icon-buttons' (collapses to menu on mobile)
* - 'detail'/'form' variants → 'primary-buttons' (fixed bottom on mobile)
*/
actions?: PageActionButton[]
/**
* Override the automatically determined PageActions variant
*/
actionsVariant?: 'icon-buttons' | 'primary-buttons' | 'menu-primary'
/**
* Page action menu items configuration
*/
menuActions?: ActionsMenuGroup[]
/**
* Custom header content (overrides title/subtitle)
*/
headerContent?: React.ReactNode
/**
* Container padding
*/
padding?: 'none' | 'sm' | 'md' | 'lg'
/**
* Container background
*/
background?: 'default' | 'card' | 'transparent'
/**
* Additional CSS classes for container
*/
className?: string
/**
* Additional CSS classes for content area
*/
contentClassName?: string
/**
* Whether to show the standard header section
*/
showHeader?: boolean
}
// Union type that supports both interfaces
export type PageContainerProps = LegacyPageContainerProps | AdvancedPageContainerProps
// Type guard to determine which interface is being used
function isAdvancedProps(props: PageContainerProps): props is AdvancedPageContainerProps {
return 'variant' in props || 'title' in props || 'subtitle' in props || 'backButton' in props || 'headerActions' in props || 'headerContent' in props || 'showHeader' in props || 'contentClassName' in props || 'actions' in props || 'actionsVariant' in props
}
/**
* @deprecated Use `PageLayout` from `'../layout/page-layout'` instead.
*
* Unified Page Container Component
*
* Supports both legacy layout patterns and advanced UI patterns:
*
* LEGACY USAGE (backward compatible):
*
* Your Content
*
*
* ADVANCED USAGE (new features):
* {}}}>
* Your Content
*
*/
export function PageContainer(props: PageContainerProps) {
if (isAdvancedProps(props)) {
return renderAdvancedPageContainer(props)
} else {
return renderLegacyPageContainer(props)
}
}
// Legacy implementation (preserves original behavior exactly)
function renderLegacyPageContainer({
children,
className = '',
fullWidthBackground = true,
backgroundClassName = 'bg-ods-bg',
backgroundStyle,
contentPadding,
maxWidth = 'max-w-[1920px]',
as: Component = 'section',
id
}: LegacyPageContainerProps) {
const content = (
{children}
);
if (fullWidthBackground) {
return (
{content}
);
}
// If fullWidthBackground is false, apply background to content container only
return (
{children}
);
}
// Advanced implementation (from UI component)
function renderAdvancedPageContainer({
children,
variant = 'content',
title,
subtitle,
backButton,
headerActions,
headerContent,
actions,
actionsVariant,
menuActions,
padding = 'none',
background = 'transparent',
className,
contentClassName,
showHeader = true
}: AdvancedPageContainerProps) {
// Determine PageActions variant based on page variant
const getActionsVariant = () => {
if (actionsVariant) return actionsVariant
// List pages use icon-buttons (collapses to menu on mobile)
if (variant === 'list') return 'icon-buttons'
// Detail/form pages use primary-buttons (fixed bottom on mobile)
return 'primary-buttons'
}
// Render actions component
const renderActions = () => {
if (!actions || actions.length === 0) return null
return
}
// Check if we need bottom padding for mobile fixed actions
const needsBottomPadding = actions && actions.length > 0 && getActionsVariant() === 'primary-buttons'
const paddingClasses = {
none: '',
sm: 'p-4',
md: 'p-6',
lg: 'p-8'
}
const backgroundClasses = {
default: 'bg-ods-bg',
card: 'bg-ods-card',
transparent: ''
}
const renderHeader = () => {
if (!showHeader) return null
if (headerContent) {
return (
{headerContent}
)
}
if (variant === 'detail') {
return (
{/* Back Button */}
{backButton && (
)}
{/* Title */}
{title && (
{title}
)}
{/* Subtitle */}
{subtitle && (
{subtitle}
)}
{/* Header Actions */}
{(headerActions || actions) && (
{headerActions}
{renderActions()}
)}
)
}
if (variant === 'list') {
return (
{/* Back Button */}
{backButton && (
)}
{title && (
{title}
)}
{subtitle && (
{subtitle}
)}
{/* Header Actions */}
{(headerActions || actions) && (
{headerActions}
{renderActions()}
)}
)
}
if (variant === 'form') {
return (
{/* Back Button */}
{backButton && (
)}
{title && (
{title}
)}
{/* Header Actions */}
{(headerActions || actions) && (
{headerActions}
{renderActions()}
)}
)
}
// Default content header
return (
{(title || subtitle) && (
{title && (
{title}
)}
{subtitle && (
{subtitle}
)}
)}
{(headerActions || actions) && (
{headerActions}
{renderActions()}
)}
)
}
const getContainerClasses = () => {
const baseClasses = [
'flex flex-col w-full',
backgroundClasses[background],
paddingClasses[padding]
]
switch (variant) {
case 'list':
return cn(baseClasses, 'gap-4 md:gap-6', className)
case 'detail':
return cn(baseClasses, 'gap-4 md:gap-6', className)
case 'form':
return cn(baseClasses, 'gap-6 md:gap-10', className)
case 'content':
default:
return cn(baseClasses, 'gap-4 md:gap-6', className)
}
}
const getContentClasses = () => {
// Add bottom padding on mobile when using primary-buttons variant (fixed bottom bar)
const mobilePadding = needsBottomPadding ? 'pb-28 md:pb-0' : ''
switch (variant) {
case 'detail':
return cn('flex-1 overflow-auto', mobilePadding, contentClassName)
case 'list':
return cn('flex flex-col gap-4 md:gap-6', mobilePadding, contentClassName)
case 'form':
return cn('flex flex-col gap-4 md:gap-10', mobilePadding, contentClassName)
case 'content':
default:
return cn('flex-1', mobilePadding, contentClassName)
}
}
return (
{renderHeader()}
{children}
)
}
/** @deprecated Use `PageLayout` from `'../layout/page-layout'` instead. */
export const ListPageContainer = (props: Omit) =>
/** @deprecated Use `PageLayout` from `'../layout/page-layout'` instead. */
export const DetailPageContainer = (props: Omit) =>
/** @deprecated Use `PageLayout` from `'../layout/page-layout'` instead. */
export const FormPageContainer = (props: Omit) =>
/** @deprecated Use `PageLayout` from `'../layout/page-layout'` instead. */
export const ContentPageContainer = (props: Omit) =>
// Re-export PageActionButton type for convenience
export type { PageActionButton } from '../ui/page-actions'
/** @deprecated Use `PageLayout` from `'../layout/page-layout'` instead. */
export default PageContainer;