import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import {
Sparkles,
Palette,
Type,
Shapes,
MousePointerClick,
FileEdit,
LayoutGrid,
SlidersHorizontal,
Compass,
Home,
Mail,
Phone,
User,
Users,
Bell,
TrendingUp,
Rocket,
Search,
ChevronsUpDown,
} from 'lucide-react';
import { useBrandColors } from '../../../contexts/BrandColorsContext';
import { useOptionalLayout } from '../../../contexts/LayoutContext';
import { cn } from '../../shared/utils';
import { Header } from '../../layout/header';
import { PageHeader } from '../../ui/page-header';
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from '../../ui/card';
import { Separator } from '../../ui/separator';
import { Badge } from '../../ui/badge';
import { Button } from '../../ui/button';
import { Input } from '../../ui/input';
import { Label } from '../../ui/label';
import { Textarea } from '../../ui/textarea';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../ui/select';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '../../ui/tabs';
import { Alert, AlertTitle, AlertDescription } from '../../ui/alert';
import { Progress } from '../../ui/progress';
import { Skeleton } from '../../ui/skeleton';
import { Empty, EmptyIcon, EmptyTitle, EmptyDescription, EmptyAction } from '../../ui/empty';
import { Avatar, AvatarImage, AvatarFallback } from '../../ui/avatar';
import { StatsCard } from '../../ui/stats-card';
import {
Timeline,
TimelineItem,
TimelineDot,
TimelineContent,
TimelineHeading,
TimelineTime,
TimelineDescription,
} from '../../ui/timeline';
import { Checkbox } from '../../ui/checkbox';
import { RadioGroup, RadioGroupItem } from '../../ui/radio-group';
import { Switch } from '../../ui/switch';
import { Slider } from '../../ui/slider';
import { ToggleGroup, ToggleGroupItem } from '../../ui/toggle-group';
import { InputOTP, InputOTPGroup, InputOTPSlot } from '../../ui/input-otp';
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogFooter,
} from '../../ui/dialog';
import { Popover, PopoverTrigger, PopoverContent } from '../../ui/popover';
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '../../ui/tooltip';
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
} from '../../ui/dropdown-menu';
import { HoverCard, HoverCardTrigger, HoverCardContent } from '../../ui/hover-card';
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '../../ui/accordion';
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from '../../ui/collapsible';
import {
Pagination,
PaginationContent,
PaginationItem,
PaginationLink,
PaginationPrevious,
PaginationNext,
} from '../../ui/pagination';
import {
FeatureCard,
QuickActionCard,
ActivityCard,
NotificationCard,
ProfileCard,
ProjectCard,
type ActivityItem,
type NotificationItem,
} from '../../blocks/card-patterns';
import { ThemeToggle } from '../../brand/theme-toggle';
import { LanguageSelector } from '../../brand/language-selector';
import { Isotipo, Mosaico, Cuadrados } from '../../brand/isotype';
import { XerticaLogo } from '../../brand/xertica-logo';
import { XerticaXLogo } from '../../brand/xertica-xlogo';
export interface ShowcaseContentProps {
/**
* Brand theme id to switch to on mount (e.g. `"xertica"`). Left undefined
* by default so embedding this content inside a host app never hijacks its
* active theme — only the standalone `ShowcasePage` opts into this.
*/
defaultThemeId?: string;
}
const TYPOGRAPHY_SCALE = [
{
key: 'hero',
family: 'heading',
weight: 'Heavy 900',
size: '60px',
lineHeight: '105%',
tracking: '-2px',
},
{
key: 'h1',
family: 'heading',
weight: 'Bold 700',
size: '44px',
lineHeight: '120%',
tracking: '-1.5px',
},
{
key: 'h2',
family: 'heading',
weight: 'Bold 700',
size: '32px',
lineHeight: '125%',
tracking: '-1px',
},
{
key: 'h3',
family: 'heading',
weight: 'Bold 700',
size: '24px',
lineHeight: '130%',
tracking: '-0.5px',
},
{
key: 'body',
family: 'body',
weight: 'Regular 400',
size: '18px',
lineHeight: '165%',
tracking: 'normal',
},
{
key: 'eyebrow',
family: 'body',
weight: 'Medium 500',
size: '13px',
lineHeight: '150%',
tracking: '1.5px',
},
{
key: 'nav',
family: 'body',
weight: 'Regular/Medium',
size: '15–16px',
lineHeight: '150%',
tracking: 'normal',
},
{
key: 'button',
family: 'body',
weight: 'Semibold/Bold 600–700',
size: '15–16px',
lineHeight: '120%',
tracking: '-0.2px',
},
] as const;
const TYPOGRAPHY_FONT_SIZE: Record<(typeof TYPOGRAPHY_SCALE)[number]['key'], string> = {
hero: '60px',
h1: '44px',
h2: '32px',
h3: '24px',
body: '18px',
eyebrow: '13px',
nav: '16px',
button: '16px',
};
const ACCENT_PALETTE = [
{ name: 'Negro Xertica', hex: '#1E1E1E' },
{ name: 'Azul', hex: '#3D63AC' },
{ name: 'Celeste', hex: '#1899AF' },
{ name: 'Magenta', hex: '#C45BAA' },
{ name: 'Rojo Coral', hex: '#DE5B48' },
{ name: 'Rosado', hex: '#E2B8D2' },
{ name: 'Amarillo', hex: '#FAF338' },
{ name: 'Naranja', hex: '#E37744' },
{ name: 'Verde', hex: '#2E8B5A' },
{ name: 'Verde azulado', hex: '#39C6AE' },
];
const SURFACE_PALETTE = [
{ name: 'Marfil', hex: '#FFFEF8' },
{ name: 'Crema / Papel', hex: '#F2EDD8' },
{ name: 'Fondo Slides', hex: '#F5F0E8' },
{ name: 'Off-white cálido', hex: '#E9E6DC' },
];
const APPROVED_COMBINATIONS = [
['#1899AF', '#DE5B48'],
['#DE5B48', '#3D63AC', '#E2B8D2'],
['#DE5B48', '#2E8B5A', '#E2B8D2'],
['#FAF338', '#DE5B48'],
['#C45BAA', '#1899AF'],
];
const INTERSECTIONS = [
{ a: '#1899AF', b: '#C45BAA', result: '#5A4A96', obligatory: true },
{ a: '#2E8B5A', b: '#DE5B48', result: '#2A2415', obligatory: true },
{ a: '#1899AF', b: '#FAF338', result: '#2E9A3A', obligatory: false },
];
const SAMPLE_ACTIVITY_ITEMS: ActivityItem[] = [
{
id: 'a1',
user: { name: 'Alex Rivera', initials: 'AR' },
action: 'updated',
target: 'Showcase Page',
time: '2m',
type: 'update',
},
{
id: 'a2',
user: { name: 'Mia Chen', initials: 'MC' },
action: 'deployed',
target: 'v3.1.0',
time: '1h',
type: 'deploy',
},
{
id: 'a3',
user: { name: 'Diego Torres', initials: 'DT' },
action: 'commented on',
target: 'Brand tokens',
time: '3h',
type: 'comment',
},
];
const SAMPLE_NOTIFICATION_ITEMS: NotificationItem[] = [
{
id: 'n1',
title: 'New theme available',
message: 'The xertica brand theme is ready to use.',
time: '5m',
read: false,
type: 'success',
},
{
id: 'n2',
title: 'Token update',
message: '--card-hover-shadow now resolves to none.',
time: '1h',
read: false,
type: 'info',
},
{
id: 'n3',
title: 'Review requested',
message: 'Please review the button press-shift spec.',
time: '1d',
read: true,
type: 'default',
},
];
function SectionHeading({
icon,
title,
description,
}: {
icon: React.ReactNode;
title: string;
description?: string;
}) {
return (
{icon}
{title}
{description &&
{description}
}
);
}
function StaticSwatch({ name, hex }: { name: string; hex: string }) {
return (
);
}
export function ShowcaseContent({ defaultThemeId }: ShowcaseContentProps) {
const { t } = useTranslation();
const { currentTheme, themes, setTheme } = useBrandColors();
const layout = useOptionalLayout();
const sidebarExpanded = layout?.sidebarExpanded ?? false;
const sidebarWidth = layout?.sidebarWidth ?? 280;
useEffect(() => {
if (defaultThemeId) {
setTheme(defaultThemeId);
}
// Only ever applied once, on mount — never re-forced if the visitor picks a different theme.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const [progress, setProgress] = useState(64);
const [otpValue, setOtpValue] = useState('');
const [radioValue, setRadioValue] = useState('starter');
const [checked, setChecked] = useState(true);
const [switchOn, setSwitchOn] = useState(true);
const [paginationPage, setPaginationPage] = useState(2);
const orderedThemes = [
...themes.filter(theme => theme.id === 'xertica'),
...themes.filter(theme => theme.id === 'xertica-original'),
...themes.filter(theme => theme.id !== 'xertica' && theme.id !== 'xertica-original'),
];
return (
},
{ label: t('showcase.breadcrumb') },
]}
renderLink={(href, props) =>
}
/>
{/* 0. Theme switcher */}
{t('showcase.themeSwitcher.label')}
{t('showcase.themeSwitcher.hint')}
{orderedThemes.map(theme => (
))}
{/* 1. Typography */}
}
title={t('showcase.sections.typography')}
description={t('showcase.typography.description')}
/>
{TYPOGRAPHY_SCALE.map(row => (
{t(`showcase.typography.samples.${row.key}`)}
{t(`showcase.typography.labels.${row.key}`)} — {row.weight} · {row.size} ·{' '}
{row.lineHeight} lh · {row.tracking} tracking
))}
{t('showcase.typography.footnote')}
{/* 2. Colors & surfaces */}
}
title={t('showcase.sections.colors')}
description={t('showcase.colors.description')}
/>
{t('showcase.colors.staticBadge')}
{t('showcase.colors.accentPalette')}
{ACCENT_PALETTE.map(color => (
))}
{t('showcase.colors.surfaces')}
{SURFACE_PALETTE.map(surface => (
))}
{t('showcase.colors.intersections')}
{t('showcase.colors.intersectionsHint')}
{INTERSECTIONS.map(pair => (
+
=
{pair.result}
{pair.obligatory && (
{t('showcase.colors.obligatory')}
)}
))}
{t('showcase.colors.combinations')}
{APPROVED_COMBINATIONS.map((combo, index) => (
{combo.map((hex, hexIndex) => (
))}
))}
{/* 3. Isotypes & logo */}
}
title={t('showcase.sections.brandMarks')}
description={t('showcase.brandMarks.description')}
/>
{(['blue-magenta', 'blue-yellow', 'green-red'] as const).map(variant => (
))}
{(['magenta-blue', 'blue-red', 'green-red'] as const).map(variant => (
))}
XerticaLogo · default
XerticaLogo · white
XerticaXLogo
{t('showcase.brandMarks.neverTitle')}
- {t('showcase.brandMarks.never.gradients')}
- {t('showcase.brandMarks.never.metallic')}
- {t('showcase.brandMarks.never.decorativeFonts')}
- {t('showcase.brandMarks.never.textOverShapes')}
- {t('showcase.brandMarks.never.floatingShapes')}
- {t('showcase.brandMarks.never.logoAbuse')}
{/* 4. Buttons */}
}
title={t('showcase.sections.buttons')}
description={t('showcase.buttons.description')}
/>
{t('showcase.buttons.segmentedA')}
{t('showcase.buttons.segmentedB')}
{t('showcase.buttons.segmentedC')}
{t('showcase.buttons.footnote')}
{/* 5. Forms */}
}
title={t('showcase.sections.forms')}
description={t('showcase.forms.description')}
/>
{t('showcase.forms.footnote')}
{/* 6. Cards */}
}
title={t('showcase.sections.cards')}
description={t('showcase.cards.description')}
/>
}
color="chart-3"
badge={t('showcase.cards.new')}
actionLabel={t('showcase.cards.learnMore')}
/>
}
actionLabel={t('showcase.cards.run')}
/>
{t('showcase.cards.footnote')}
{/* 7. Controls */}
}
title={t('showcase.sections.controls')}
description={t('showcase.controls.description')}
/>
{t('showcase.controls.themeMode')}
{t('showcase.controls.language')}
{t('showcase.controls.footnote')}
{/* 8. Explore more */}
}
title={t('showcase.sections.exploreMore')}
description={t('showcase.exploreMore.description')}
/>
{t('showcase.exploreMore.tabs.feedback')}
{t('showcase.exploreMore.tabs.data')}
{t('showcase.exploreMore.tabs.navigation')}
{t('showcase.exploreMore.tabs.overlays')}
Alert
{t('showcase.exploreMore.alertBody')}
setProgress(value)}
max={100}
step={1}
/>
{t('showcase.exploreMore.emptyTitle')}
{t('showcase.exploreMore.emptyDescription')}
}
/>
XA
setChecked(!!value)}
/>
{t('showcase.exploreMore.timelineDone')}
Aug 2026
{t('showcase.exploreMore.timelineDoneBody')}
{t('showcase.exploreMore.timelinePending')}
{t('showcase.exploreMore.timelinePendingBody')}
{
event.preventDefault();
setPaginationPage(page => Math.max(1, page - 1));
}}
/>
{[1, 2, 3].map(page => (
{
event.preventDefault();
setPaginationPage(page);
}}
>
{page}
))}
{
event.preventDefault();
setPaginationPage(page => Math.min(3, page + 1));
}}
/>
{t('showcase.exploreMore.accordionQuestion')}
{t('showcase.exploreMore.accordionAnswer')}
{t('showcase.exploreMore.collapsibleLabel')}
{t('showcase.exploreMore.collapsibleBody')}
{t('showcase.exploreMore.popoverBody')}
{t('showcase.exploreMore.tooltipBody')}
{t('showcase.exploreMore.hoverCardBody')}
{t('showcase.exploreMore.menuLabel')}
{t('showcase.exploreMore.menuProfile')}
{t('showcase.exploreMore.menuSettings')}
{t('showcase.exploreMore.footnote')}
);
}