- Add state to track selected article (sectionId + articleId) - Implement renderArticleContent() function to display full article content - Display intro, steps, tips, and conclusion sections from translations - Add click handlers to article cards to show detail view - Add back button to return to article list - Reset selected article when switching sections in sidebar Fixes issue where clicking on article cards only showed metadata instead of full content with steps, tips, and detailed information.
749 lines
29 KiB
TypeScript
749 lines
29 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { Link } from 'react-router-dom';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { PublicLayout } from '../../components/layout';
|
|
import {
|
|
FileText,
|
|
BookOpen,
|
|
Rocket,
|
|
Package,
|
|
BarChart3,
|
|
Settings,
|
|
Users,
|
|
Shield,
|
|
CreditCard,
|
|
HelpCircle,
|
|
ChevronRight,
|
|
PlayCircle,
|
|
CheckCircle2,
|
|
AlertCircle,
|
|
Info,
|
|
Download,
|
|
ExternalLink
|
|
} from 'lucide-react';
|
|
|
|
interface DocSection {
|
|
id: string;
|
|
title: string;
|
|
description: string;
|
|
icon: React.ComponentType<{ className?: string }>;
|
|
articles: DocArticle[];
|
|
}
|
|
|
|
interface DocArticle {
|
|
id: string;
|
|
title: string;
|
|
description: string;
|
|
readTime: string;
|
|
difficulty: 'beginner' | 'intermediate' | 'advanced';
|
|
}
|
|
|
|
const DocumentationPage: React.FC = () => {
|
|
const { t } = useTranslation('help');
|
|
const [activeSection, setActiveSection] = useState<string>('getting-started');
|
|
const [selectedArticle, setSelectedArticle] = useState<{ sectionId: string; articleId: string } | null>(null);
|
|
|
|
const sections: DocSection[] = [
|
|
{
|
|
id: 'getting-started',
|
|
title: t('categories.gettingStarted.title'),
|
|
description: t('categories.gettingStarted.description'),
|
|
icon: Rocket,
|
|
articles: [
|
|
{
|
|
id: 'quick-start',
|
|
title: t('articles.gettingStarted.quickStart.title'),
|
|
description: t('articles.gettingStarted.quickStart.description'),
|
|
readTime: `${t('articles.gettingStarted.quickStart.readTime')} ${t('docs.readTime')}`,
|
|
difficulty: 'beginner',
|
|
},
|
|
{
|
|
id: 'import-data',
|
|
title: t('articles.gettingStarted.importData.title'),
|
|
description: t('articles.gettingStarted.importData.description'),
|
|
readTime: `${t('articles.gettingStarted.importData.readTime')} ${t('docs.readTime')}`,
|
|
difficulty: 'beginner',
|
|
},
|
|
{
|
|
id: 'products-catalog',
|
|
title: t('articles.gettingStarted.productsCatalog.title'),
|
|
description: t('articles.gettingStarted.productsCatalog.description'),
|
|
readTime: `${t('articles.gettingStarted.productsCatalog.readTime')} ${t('docs.readTime')}`,
|
|
difficulty: 'beginner',
|
|
},
|
|
{
|
|
id: 'first-prediction',
|
|
title: t('articles.gettingStarted.firstPrediction.title'),
|
|
description: t('articles.gettingStarted.firstPrediction.description'),
|
|
readTime: `${t('articles.gettingStarted.firstPrediction.readTime')} ${t('docs.readTime')}`,
|
|
difficulty: 'beginner',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'features',
|
|
title: t('categories.features.title'),
|
|
description: t('categories.features.description'),
|
|
icon: Package,
|
|
articles: [
|
|
{
|
|
id: 'demand-forecasting',
|
|
title: t('articles.features.demandForecasting.title'),
|
|
description: t('articles.features.demandForecasting.description'),
|
|
readTime: `${t('articles.features.demandForecasting.readTime')} ${t('docs.readTime')}`,
|
|
difficulty: 'intermediate',
|
|
},
|
|
{
|
|
id: 'production-planning',
|
|
title: t('articles.features.productionPlanning.title'),
|
|
description: t('articles.features.productionPlanning.description'),
|
|
readTime: `${t('articles.features.productionPlanning.readTime')} ${t('docs.readTime')}`,
|
|
difficulty: 'intermediate',
|
|
},
|
|
{
|
|
id: 'inventory-management',
|
|
title: t('articles.features.inventoryManagement.title'),
|
|
description: t('articles.features.inventoryManagement.description'),
|
|
readTime: `${t('articles.features.inventoryManagement.readTime')} ${t('docs.readTime')}`,
|
|
difficulty: 'intermediate',
|
|
},
|
|
{
|
|
id: 'pos-integration',
|
|
title: t('articles.features.posIntegration.title'),
|
|
description: t('articles.features.posIntegration.description'),
|
|
readTime: `${t('articles.features.posIntegration.readTime')} ${t('docs.readTime')}`,
|
|
difficulty: 'beginner',
|
|
},
|
|
{
|
|
id: 'waste-tracking',
|
|
title: t('articles.features.wasteTracking.title'),
|
|
description: t('articles.features.wasteTracking.description'),
|
|
readTime: `${t('articles.features.wasteTracking.readTime')} ${t('docs.readTime')}`,
|
|
difficulty: 'beginner',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'analytics',
|
|
title: t('categories.analytics.title'),
|
|
description: t('categories.analytics.description'),
|
|
icon: BarChart3,
|
|
articles: [
|
|
{
|
|
id: 'dashboard-overview',
|
|
title: t('articles.analytics.dashboardOverview.title'),
|
|
description: t('articles.analytics.dashboardOverview.description'),
|
|
readTime: `${t('articles.analytics.dashboardOverview.readTime')} ${t('docs.readTime')}`,
|
|
difficulty: 'beginner',
|
|
},
|
|
{
|
|
id: 'reports',
|
|
title: t('articles.analytics.reports.title'),
|
|
description: t('articles.analytics.reports.description'),
|
|
readTime: `${t('articles.analytics.reports.readTime')} ${t('docs.readTime')}`,
|
|
difficulty: 'intermediate',
|
|
},
|
|
{
|
|
id: 'ai-insights',
|
|
title: t('articles.analytics.aiInsights.title'),
|
|
description: t('articles.analytics.aiInsights.description'),
|
|
readTime: `${t('articles.analytics.aiInsights.readTime')} ${t('docs.readTime')}`,
|
|
difficulty: 'advanced',
|
|
},
|
|
{
|
|
id: 'performance-metrics',
|
|
title: t('articles.analytics.performanceMetrics.title'),
|
|
description: t('articles.analytics.performanceMetrics.description'),
|
|
readTime: `${t('articles.analytics.performanceMetrics.readTime')} ${t('docs.readTime')}`,
|
|
difficulty: 'intermediate',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'account',
|
|
title: t('categories.account.title'),
|
|
description: t('categories.account.description'),
|
|
icon: Settings,
|
|
articles: [
|
|
{
|
|
id: 'profile-settings',
|
|
title: 'Configuración de Perfil',
|
|
description: 'Actualiza tu información personal y preferencias',
|
|
readTime: '4 min',
|
|
difficulty: 'beginner',
|
|
},
|
|
{
|
|
id: 'team-management',
|
|
title: 'Gestionar Equipo',
|
|
description: 'Añade miembros, asigna roles y permisos',
|
|
readTime: '7 min',
|
|
difficulty: 'intermediate',
|
|
},
|
|
{
|
|
id: 'notifications',
|
|
title: 'Notificaciones y Alertas',
|
|
description: 'Configura cómo y cuándo recibir avisos',
|
|
readTime: '5 min',
|
|
difficulty: 'beginner',
|
|
},
|
|
{
|
|
id: 'integrations',
|
|
title: 'Integraciones',
|
|
description: 'Conecta con TPV, contabilidad y otras herramientas',
|
|
readTime: '10 min',
|
|
difficulty: 'advanced',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'billing',
|
|
title: t('categories.billing.title'),
|
|
description: t('categories.billing.description'),
|
|
icon: CreditCard,
|
|
articles: [
|
|
{
|
|
id: 'pricing-plans',
|
|
title: 'Planes y Precios',
|
|
description: 'Compara características de cada plan',
|
|
readTime: '6 min',
|
|
difficulty: 'beginner',
|
|
},
|
|
{
|
|
id: 'payment-methods',
|
|
title: 'Métodos de Pago',
|
|
description: 'Añade, modifica o elimina tarjetas',
|
|
readTime: '4 min',
|
|
difficulty: 'beginner',
|
|
},
|
|
{
|
|
id: 'invoices',
|
|
title: 'Facturas y Recibos',
|
|
description: 'Descarga y gestiona tu historial de facturación',
|
|
readTime: '5 min',
|
|
difficulty: 'beginner',
|
|
},
|
|
{
|
|
id: 'cancel-subscription',
|
|
title: 'Cancelar o Pausar Suscripción',
|
|
description: 'Cómo proceder si necesitas hacer una pausa',
|
|
readTime: '3 min',
|
|
difficulty: 'beginner',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'privacy',
|
|
title: t('categories.privacy.title'),
|
|
description: t('categories.privacy.description'),
|
|
icon: Shield,
|
|
articles: [
|
|
{
|
|
id: 'gdpr-compliance',
|
|
title: 'Cumplimiento RGPD',
|
|
description: 'Cómo protegemos tus datos según normativa europea',
|
|
readTime: '10 min',
|
|
difficulty: 'intermediate',
|
|
},
|
|
{
|
|
id: 'data-export',
|
|
title: 'Exportar Tus Datos',
|
|
description: 'Descarga toda tu información en cualquier momento',
|
|
readTime: '5 min',
|
|
difficulty: 'beginner',
|
|
},
|
|
{
|
|
id: 'data-deletion',
|
|
title: 'Eliminar Tu Cuenta',
|
|
description: 'Procedimiento para borrar permanentemente tus datos',
|
|
readTime: '6 min',
|
|
difficulty: 'beginner',
|
|
},
|
|
{
|
|
id: 'security-best-practices',
|
|
title: 'Mejores Prácticas de Seguridad',
|
|
description: 'Protege tu cuenta con 2FA y contraseñas fuertes',
|
|
readTime: '8 min',
|
|
difficulty: 'intermediate',
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
const activeContent = sections.find((s) => s.id === activeSection);
|
|
|
|
const getDifficultyColor = (difficulty: string) => {
|
|
switch (difficulty) {
|
|
case 'beginner':
|
|
return 'text-green-600 dark:text-green-400';
|
|
case 'intermediate':
|
|
return 'text-amber-600 dark:text-amber-400';
|
|
case 'advanced':
|
|
return 'text-red-600 dark:text-red-400';
|
|
default:
|
|
return 'text-[var(--text-tertiary)]';
|
|
}
|
|
};
|
|
|
|
const getDifficultyLabel = (difficulty: string) => {
|
|
return t(`difficulty.${difficulty}` as any) || difficulty;
|
|
};
|
|
|
|
const getCategoryKey = (sectionId: string): string => {
|
|
const categoryMap: Record<string, string> = {
|
|
'getting-started': 'gettingStarted',
|
|
'features': 'features',
|
|
'analytics': 'analytics',
|
|
'account': 'account',
|
|
'billing': 'billing',
|
|
'privacy': 'privacy',
|
|
};
|
|
return categoryMap[sectionId] || sectionId;
|
|
};
|
|
|
|
const getArticleKey = (articleId: string): string => {
|
|
const articleMap: Record<string, string> = {
|
|
'quick-start': 'quickStart',
|
|
'import-data': 'importData',
|
|
'products-catalog': 'productsCatalog',
|
|
'first-prediction': 'firstPrediction',
|
|
'demand-forecasting': 'demandForecasting',
|
|
'production-planning': 'productionPlanning',
|
|
'inventory-management': 'inventoryManagement',
|
|
'pos-integration': 'posIntegration',
|
|
'waste-tracking': 'wasteTracking',
|
|
'dashboard-overview': 'dashboardOverview',
|
|
'reports': 'reports',
|
|
'ai-insights': 'aiInsights',
|
|
'performance-metrics': 'performanceMetrics',
|
|
};
|
|
return articleMap[articleId] || articleId;
|
|
};
|
|
|
|
const handleArticleClick = (sectionId: string, articleId: string) => {
|
|
setSelectedArticle({ sectionId, articleId });
|
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
|
};
|
|
|
|
const handleBackToList = () => {
|
|
setSelectedArticle(null);
|
|
};
|
|
|
|
const renderArticleContent = () => {
|
|
if (!selectedArticle) return null;
|
|
|
|
const categoryKey = getCategoryKey(selectedArticle.sectionId);
|
|
const articleKey = getArticleKey(selectedArticle.articleId);
|
|
const contentPath = `articles.${categoryKey}.${articleKey}.content`;
|
|
|
|
const content: any = t(contentPath, { returnObjects: true });
|
|
const article = sections
|
|
.find((s) => s.id === selectedArticle.sectionId)
|
|
?.articles.find((a) => a.id === selectedArticle.articleId);
|
|
|
|
if (!article || !content) return null;
|
|
|
|
return (
|
|
<div>
|
|
{/* Back Button */}
|
|
<button
|
|
onClick={handleBackToList}
|
|
className="mb-6 flex items-center gap-2 text-[var(--color-primary)] hover:underline"
|
|
>
|
|
<ChevronRight className="w-5 h-5 transform rotate-180" />
|
|
<span>{t('docs.backToHelp')}</span>
|
|
</button>
|
|
|
|
{/* Article Header */}
|
|
<div className="mb-8 pb-8 border-b border-[var(--border-primary)]">
|
|
<h1 className="text-4xl font-extrabold text-[var(--text-primary)] mb-4">
|
|
{article.title}
|
|
</h1>
|
|
<p className="text-xl text-[var(--text-secondary)] mb-4">{article.description}</p>
|
|
<div className="flex items-center gap-4 text-sm">
|
|
<span className="flex items-center gap-1 text-[var(--text-tertiary)]">
|
|
<PlayCircle className="w-4 h-4" />
|
|
{article.readTime}
|
|
</span>
|
|
<span className={`font-medium ${getDifficultyColor(article.difficulty)}`}>
|
|
{getDifficultyLabel(article.difficulty)}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Article Content */}
|
|
<div className="prose prose-lg dark:prose-invert max-w-none">
|
|
{/* Intro */}
|
|
{content.intro && (
|
|
<div className="bg-[var(--color-primary)]/5 border-l-4 border-[var(--color-primary)] p-6 rounded-r-xl mb-8">
|
|
<p className="text-[var(--text-primary)] text-lg leading-relaxed m-0">
|
|
{content.intro}
|
|
</p>
|
|
</div>
|
|
)}
|
|
|
|
{/* Steps */}
|
|
{content.steps && Array.isArray(content.steps) && (
|
|
<div className="space-y-6 mb-8">
|
|
{content.steps.map((step: any, index: number) => (
|
|
<div
|
|
key={index}
|
|
className="bg-[var(--bg-secondary)] rounded-xl p-6 border border-[var(--border-primary)]"
|
|
>
|
|
<h3 className="text-xl font-bold text-[var(--text-primary)] mb-3 mt-0">
|
|
{step.title}
|
|
</h3>
|
|
<p className="text-[var(--text-secondary)] leading-relaxed m-0">
|
|
{step.description}
|
|
</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
{/* Tips */}
|
|
{content.tips && Array.isArray(content.tips) && content.tips.length > 0 && (
|
|
<div className="bg-amber-50 dark:bg-amber-900/20 border-2 border-amber-200 dark:border-amber-800 rounded-xl p-6 mb-8">
|
|
<h3 className="text-xl font-bold text-[var(--text-primary)] mb-4 mt-0 flex items-center gap-2">
|
|
<Info className="w-6 h-6 text-amber-600" />
|
|
<span>Consejos Útiles</span>
|
|
</h3>
|
|
<ul className="space-y-2 m-0 pl-0 list-none">
|
|
{content.tips.map((tip: string, index: number) => (
|
|
<li key={index} className="flex items-start gap-3">
|
|
<CheckCircle2 className="w-5 h-5 text-amber-600 flex-shrink-0 mt-0.5" />
|
|
<span className="text-[var(--text-secondary)]">{tip}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
)}
|
|
|
|
{/* Conclusion */}
|
|
{content.conclusion && (
|
|
<div className="bg-green-50 dark:bg-green-900/20 border-l-4 border-green-600 p-6 rounded-r-xl">
|
|
<p className="text-[var(--text-primary)] leading-relaxed m-0">
|
|
{content.conclusion}
|
|
</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Back to List Button */}
|
|
<div className="mt-12 pt-8 border-t border-[var(--border-primary)]">
|
|
<button
|
|
onClick={handleBackToList}
|
|
className="flex items-center gap-2 px-6 py-3 bg-[var(--color-primary)] text-white rounded-xl font-bold hover:shadow-xl transition-all"
|
|
>
|
|
<ChevronRight className="w-5 h-5 transform rotate-180" />
|
|
<span>Volver a la Lista</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<PublicLayout
|
|
variant="default"
|
|
contentPadding="md"
|
|
headerProps={{
|
|
showThemeToggle: true,
|
|
showAuthButtons: true,
|
|
showLanguageSelector: true,
|
|
variant: 'default',
|
|
}}
|
|
>
|
|
{/* Hero Section */}
|
|
<section className="bg-gradient-to-br from-[var(--bg-primary)] via-[var(--bg-secondary)] to-[var(--color-primary)]/5 py-20">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div className="text-center max-w-4xl mx-auto">
|
|
<div className="inline-flex items-center gap-2 bg-[var(--color-primary)]/10 text-[var(--color-primary)] px-4 py-2 rounded-full text-sm font-medium mb-6">
|
|
<FileText className="w-4 h-4" />
|
|
<span>{t('docs.subtitle')}</span>
|
|
</div>
|
|
<h1 className="text-4xl lg:text-6xl font-extrabold text-[var(--text-primary)] mb-6">
|
|
{t('docs.title')}
|
|
</h1>
|
|
<p className="text-xl text-[var(--text-secondary)] leading-relaxed mb-8">
|
|
{t('docs.description')}
|
|
</p>
|
|
|
|
{/* Quick Actions */}
|
|
<div className="flex flex-wrap justify-center gap-4">
|
|
<a
|
|
href="#getting-started"
|
|
onClick={() => setActiveSection('getting-started')}
|
|
className="inline-flex items-center gap-2 px-6 py-3 bg-[var(--color-primary)] text-white rounded-xl font-bold hover:shadow-xl transition-all hover:scale-105"
|
|
>
|
|
<Rocket className="w-5 h-5" />
|
|
<span>{t('docs.getStarted')}</span>
|
|
</a>
|
|
<Link
|
|
to="/help"
|
|
className="inline-flex items-center gap-2 px-6 py-3 border-2 border-[var(--border-primary)] text-[var(--text-primary)] rounded-xl font-medium hover:border-[var(--color-primary)] transition-all"
|
|
>
|
|
<HelpCircle className="w-5 h-5" />
|
|
<span>{t('docs.backToHelp')}</span>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Documentation Content */}
|
|
<section className="py-20 bg-[var(--bg-primary)]">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div className="grid lg:grid-cols-4 gap-8">
|
|
{/* Sidebar Navigation */}
|
|
<div className="lg:col-span-1">
|
|
<div className="sticky top-8">
|
|
<h3 className="text-lg font-bold text-[var(--text-primary)] mb-4">
|
|
{t('docs.sectionsTitle')}
|
|
</h3>
|
|
<nav className="space-y-2">
|
|
{sections.map((section) => (
|
|
<button
|
|
key={section.id}
|
|
onClick={() => {
|
|
setActiveSection(section.id);
|
|
setSelectedArticle(null);
|
|
}}
|
|
className={`w-full flex items-center gap-3 px-4 py-3 rounded-xl text-left transition-all ${
|
|
activeSection === section.id
|
|
? 'bg-[var(--color-primary)] text-white'
|
|
: 'bg-[var(--bg-secondary)] text-[var(--text-primary)] hover:bg-[var(--color-primary)]/10'
|
|
}`}
|
|
>
|
|
<section.icon className="w-5 h-5 flex-shrink-0" />
|
|
<div className="flex-1 min-w-0">
|
|
<div className="font-medium truncate">{section.title}</div>
|
|
<div
|
|
className={`text-xs ${
|
|
activeSection === section.id ? 'text-white/80' : 'text-[var(--text-tertiary)]'
|
|
}`}
|
|
>
|
|
{section.articles.length} {t('docs.articlesCount')}
|
|
</div>
|
|
</div>
|
|
</button>
|
|
))}
|
|
</nav>
|
|
|
|
{/* Quick Links */}
|
|
<div className="mt-8 p-4 bg-[var(--bg-secondary)] rounded-xl border border-[var(--border-primary)]">
|
|
<h4 className="font-bold text-[var(--text-primary)] mb-3 text-sm">
|
|
{t('docs.quickLinks')}
|
|
</h4>
|
|
<div className="space-y-2 text-sm">
|
|
<Link
|
|
to="/help"
|
|
className="flex items-center gap-2 text-[var(--text-secondary)] hover:text-[var(--color-primary)] transition-colors"
|
|
>
|
|
<HelpCircle className="w-4 h-4" />
|
|
<span>{t('docs.backToHelp')}</span>
|
|
</Link>
|
|
<Link
|
|
to="/help/support"
|
|
className="flex items-center gap-2 text-[var(--text-secondary)] hover:text-[var(--color-primary)] transition-colors"
|
|
>
|
|
<ExternalLink className="w-4 h-4" />
|
|
<span>{t('docs.contactSupport')}</span>
|
|
</Link>
|
|
<a
|
|
href="#"
|
|
className="flex items-center gap-2 text-[var(--text-secondary)] hover:text-[var(--color-primary)] transition-colors"
|
|
>
|
|
<Download className="w-4 h-4" />
|
|
<span>{t('docs.downloadPdf')}</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Main Content */}
|
|
<div className="lg:col-span-3">
|
|
{selectedArticle ? (
|
|
renderArticleContent()
|
|
) : (
|
|
activeContent && (
|
|
<div>
|
|
{/* Section Header */}
|
|
<div className="mb-8">
|
|
<div className="flex items-center gap-4 mb-4">
|
|
<div className="w-12 h-12 bg-[var(--color-primary)]/10 rounded-xl flex items-center justify-center">
|
|
<activeContent.icon className="w-6 h-6 text-[var(--color-primary)]" />
|
|
</div>
|
|
<div>
|
|
<h2 className="text-3xl font-extrabold text-[var(--text-primary)]">
|
|
{activeContent.title}
|
|
</h2>
|
|
<p className="text-[var(--text-secondary)]">{activeContent.description}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Articles Grid */}
|
|
<div className="space-y-4">
|
|
{activeContent.articles.map((article) => (
|
|
<button
|
|
key={article.id}
|
|
onClick={() => handleArticleClick(activeSection, article.id)}
|
|
className="w-full block bg-[var(--bg-secondary)] rounded-xl p-6 border border-[var(--border-primary)] hover:border-[var(--color-primary)] hover:shadow-xl transition-all group text-left"
|
|
>
|
|
<div className="flex items-start justify-between gap-4">
|
|
<div className="flex-1">
|
|
<h3 className="text-xl font-bold text-[var(--text-primary)] mb-2 group-hover:text-[var(--color-primary)] transition-colors">
|
|
{article.title}
|
|
</h3>
|
|
<p className="text-[var(--text-secondary)] mb-4">{article.description}</p>
|
|
<div className="flex items-center gap-4 text-sm">
|
|
<span className="flex items-center gap-1 text-[var(--text-tertiary)]">
|
|
<PlayCircle className="w-4 h-4" />
|
|
{article.readTime}
|
|
</span>
|
|
<span className={`font-medium ${getDifficultyColor(article.difficulty)}`}>
|
|
{getDifficultyLabel(article.difficulty)}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<ChevronRight className="w-6 h-6 text-[var(--text-tertiary)] group-hover:text-[var(--color-primary)] transition-colors flex-shrink-0" />
|
|
</div>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Video Tutorials */}
|
|
<section className="py-20 bg-[var(--bg-secondary)]">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div className="text-center mb-12">
|
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-[var(--text-primary)] mb-4">
|
|
{t('docs.videoTutorialsTitle')}
|
|
</h2>
|
|
<p className="text-xl text-[var(--text-secondary)]">
|
|
{t('docs.videoTutorialsSubtitle')}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="grid md:grid-cols-3 gap-6">
|
|
{[
|
|
{
|
|
title: 'Configuración Inicial',
|
|
duration: '5:30',
|
|
thumbnail: 'getting-started',
|
|
},
|
|
{
|
|
title: 'Importar Datos Históricos',
|
|
duration: '8:15',
|
|
thumbnail: 'import-data',
|
|
},
|
|
{
|
|
title: 'Tu Primera Predicción',
|
|
duration: '12:00',
|
|
thumbnail: 'first-prediction',
|
|
},
|
|
].map((video, index) => (
|
|
<div
|
|
key={index}
|
|
className="bg-[var(--bg-primary)] rounded-xl overflow-hidden border border-[var(--border-primary)] hover:shadow-xl transition-all group"
|
|
>
|
|
<div className="aspect-video bg-gradient-to-br from-[var(--color-primary)]/20 to-orange-600/20 flex items-center justify-center relative">
|
|
<PlayCircle className="w-16 h-16 text-[var(--color-primary)] group-hover:scale-110 transition-transform" />
|
|
<div className="absolute bottom-2 right-2 bg-black/80 text-white px-2 py-1 rounded text-xs font-medium">
|
|
{video.duration}
|
|
</div>
|
|
</div>
|
|
<div className="p-4">
|
|
<h3 className="font-bold text-[var(--text-primary)] group-hover:text-[var(--color-primary)] transition-colors">
|
|
{video.title}
|
|
</h3>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Additional Resources */}
|
|
<section className="py-20 bg-[var(--bg-primary)]">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div className="text-center mb-12">
|
|
<h2 className="text-3xl lg:text-4xl font-extrabold text-[var(--text-primary)] mb-4">
|
|
{t('docs.additionalResourcesTitle')}
|
|
</h2>
|
|
</div>
|
|
|
|
<div className="grid md:grid-cols-3 gap-6">
|
|
<div className="bg-blue-50 dark:bg-blue-900/20 rounded-2xl p-6 border-2 border-blue-200 dark:border-blue-800">
|
|
<Info className="w-8 h-8 text-blue-600 mb-4" />
|
|
<h3 className="text-lg font-bold text-[var(--text-primary)] mb-2">
|
|
{t('resources.glossary.title')}
|
|
</h3>
|
|
<p className="text-sm text-[var(--text-secondary)] mb-4">
|
|
{t('resources.glossary.description')}
|
|
</p>
|
|
<a href="#glossary" className="text-blue-600 hover:underline font-medium text-sm">
|
|
{t('resources.glossary.action')} →
|
|
</a>
|
|
</div>
|
|
|
|
<div className="bg-amber-50 dark:bg-amber-900/20 rounded-2xl p-6 border-2 border-amber-200 dark:border-amber-800">
|
|
<AlertCircle className="w-8 h-8 text-amber-600 mb-4" />
|
|
<h3 className="text-lg font-bold text-[var(--text-primary)] mb-2">
|
|
{t('resources.troubleshooting.title')}
|
|
</h3>
|
|
<p className="text-sm text-[var(--text-secondary)] mb-4">
|
|
{t('resources.troubleshooting.description')}
|
|
</p>
|
|
<Link to="/help" className="text-amber-600 hover:underline font-medium text-sm">
|
|
{t('resources.troubleshooting.action')} →
|
|
</Link>
|
|
</div>
|
|
|
|
<div className="bg-green-50 dark:bg-green-900/20 rounded-2xl p-6 border-2 border-green-200 dark:border-green-800">
|
|
<CheckCircle2 className="w-8 h-8 text-green-600 mb-4" />
|
|
<h3 className="text-lg font-bold text-[var(--text-primary)] mb-2">
|
|
{t('resources.bestPractices.title')}
|
|
</h3>
|
|
<p className="text-sm text-[var(--text-secondary)] mb-4">
|
|
{t('resources.bestPractices.description')}
|
|
</p>
|
|
<a href="#best-practices" className="text-green-600 hover:underline font-medium text-sm">
|
|
{t('resources.bestPractices.action')} →
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* CTA */}
|
|
<section className="py-20 bg-gradient-to-r from-[var(--color-primary)] to-orange-600">
|
|
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
|
<h2 className="text-3xl lg:text-4xl font-bold text-white mb-6">
|
|
{t('docs.ctaTitle')}
|
|
</h2>
|
|
<p className="text-xl text-white/90 mb-8">
|
|
{t('docs.ctaSubtitle')}
|
|
</p>
|
|
<Link
|
|
to="/register"
|
|
className="inline-flex items-center gap-2 px-8 py-4 bg-white text-[var(--color-primary)] rounded-xl font-bold hover:shadow-2xl transition-all hover:scale-105"
|
|
>
|
|
<span>{t('docs.ctaButton')}</span>
|
|
<ChevronRight className="w-5 h-5" />
|
|
</Link>
|
|
</div>
|
|
</section>
|
|
</PublicLayout>
|
|
);
|
|
};
|
|
|
|
export default DocumentationPage;
|