Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
<!doctype html>
<html lang="en">
<html lang="es">

<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<title>UpSkill</title>


<title>Up-Skill - Plataforma de Cursos Online</title>
<meta name="description" content="Aprende nuevas habilidades con cursos online de calidad. Programación, desarrollo web y más con profesores expertos." />

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"prebuild": "node scripts/generate-sitemap.js",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview",
"tailwind:init": "tailwindcss init -p",
Expand All @@ -19,7 +20,8 @@
"build-storybook": "storybook build",
"cy:run": "cypress run",
"cy:open": "cypress open",
"test:e2e:local": "start-server-and-test preview http://localhost:4173 cy:run"
"test:e2e:local": "start-server-and-test preview http://localhost:4173 cy:run",
"sitemap": "node scripts/generate-sitemap.js"
},
"dependencies": {
"@blocknote/core": "^0.37.0",
Expand All @@ -33,9 +35,10 @@
"lucide-react": "^0.534.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-helmet-async": "^2.0.5",
"react-hook-form": "^7.62.0",
"react-hot-toast": "^2.6.0",
"react-router-dom": "^7.7.0",
"react-router-dom": "^7.12.0",
"recharts": "^3.1.2",
"tailwind-merge": "^3.3.1",
"three": "^0.179.1",
Expand Down
58 changes: 49 additions & 9 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added public/img/og-default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
User-agent: *
Allow: /

Sitemap: https://up-skill.app/sitemap.xml
47 changes: 47 additions & 0 deletions public/sitemap.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">

<url>
<loc>https://up-skill.app/</loc>
<lastmod>2026-01-13</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://up-skill.app/about</loc>
<lastmod>2026-01-13</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://up-skill.app/faq</loc>
<lastmod>2026-01-13</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://up-skill.app/contact</loc>
<lastmod>2026-01-13</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://up-skill.app/courses</loc>
<lastmod>2026-01-13</lastmod>
<changefreq>daily</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://up-skill.app/login</loc>
<lastmod>2026-01-13</lastmod>
<changefreq>yearly</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://up-skill.app/register</loc>
<lastmod>2026-01-13</lastmod>
<changefreq>yearly</changefreq>
<priority>0.5</priority>
</url>
</urlset>
43 changes: 43 additions & 0 deletions scripts/generate-sitemap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env node

import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const baseUrl = 'https://up-skill.app';
const currentDate = new Date().toISOString().split('T')[0];

const staticRoutes = [
{ path: '/', priority: '1.0', changefreq: 'weekly' },
{ path: '/about', priority: '0.8', changefreq: 'monthly' },
{ path: '/faq', priority: '0.7', changefreq: 'monthly' },
{ path: '/contact', priority: '0.7', changefreq: 'monthly' },
{ path: '/courses', priority: '0.9', changefreq: 'daily' },
{ path: '/login', priority: '0.5', changefreq: 'yearly' },
{ path: '/register', priority: '0.5', changefreq: 'yearly' },
];

const generateSitemap = () => {
const urls = staticRoutes.map(route => `
<url>
<loc>${baseUrl}${route.path}</loc>
<lastmod>${currentDate}</lastmod>
<changefreq>${route.changefreq}</changefreq>
<priority>${route.priority}</priority>
</url>`).join('');

const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
${urls}
</urlset>`;

const sitemapPath = path.join(__dirname, '../public/sitemap.xml');
fs.writeFileSync(sitemapPath, sitemap.trim());
console.log('✓ Sitemap generated successfully at public/sitemap.xml');
};

generateSitemap();
48 changes: 48 additions & 0 deletions src/components/common/SEO.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Helmet } from 'react-helmet-async';

interface SEOProps {
title: string;
description: string;
keywords?: string;
ogType?: 'website' | 'article';
ogImage?: string;
canonical?: string;
}

export function SEO({
title,
description,
keywords,
ogType = 'website',
ogImage = '/img/og-default.png',
canonical,
}: SEOProps) {
const fullTitle = `${title} | Up-Skill`;
const siteUrl = 'https://up-skill.app';
const canonicalUrl = canonical || typeof window !== 'undefined' ? window.location.href : siteUrl;

return (
<Helmet>
<title>{fullTitle}</title>
<meta name="description" content={description} />
{keywords && <meta name="keywords" content={keywords} />}
<link rel="canonical" href={canonicalUrl} />

<meta property="og:type" content={ogType} />
<meta property="og:title" content={fullTitle} />
<meta property="og:description" content={description} />
<meta property="og:image" content={`${siteUrl}${ogImage}`} />
<meta property="og:url" content={canonicalUrl} />
<meta property="og:site_name" content="UpSkill" />

<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={fullTitle} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={`${siteUrl}${ogImage}`} />

<meta name="robots" content="index, follow" />
<meta name="language" content="es" />
<meta name="author" content="UpSkill" />
</Helmet>
);
}
2 changes: 1 addition & 1 deletion src/components/landing/BenefitsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function BenefitsSection() {
return (
<div key={index} className="p-6 text-center space-y-4 rounded-lg bg-white/70 backdrop-blur-sm border border-slate-200 hover:border-blue-200 hover:shadow-md transition-all duration-300">
<div className="w-12 h-12 bg-gradient-to-br from-blue-400 to-green-400 rounded-full flex items-center justify-center mx-auto shadow-lg">
<IconComponent className="w-6 h-6 text-white" />
<IconComponent className="w-6 h-6 text-white" aria-hidden="true" />
</div>
<h3 className="text-lg font-poppins font-semibold text-slate-800">{benefit.title}</h3>
<p className="text-sm text-slate-600 leading-relaxed">{benefit.description}</p>
Expand Down
2 changes: 1 addition & 1 deletion src/components/landing/HeroSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function HeroSection() {
<div className="space-y-6 text-center lg:text-left">
<div className="space-y-4">
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-poppins font-bold text-slate-800 leading-tight">
Aprende sin{' '}
Cursos Online - Aprende sin{' '}
<span className="text-transparent bg-clip-text bg-gradient-to-r from-blue-500 to-green-500">
límites
</span>
Expand Down
19 changes: 19 additions & 0 deletions src/components/layouts/MainLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
import { Outlet } from 'react-router-dom';
import { NavBar } from '../common/NavBar';
import { Footer } from '../common/Footer.tsx';
import { Helmet } from 'react-helmet-async';

const MainLayout = () => {
const organizationSchema = {
"@context": "https://schema.org",
"@type": "EducationalOrganization",
"name": "Up-Skill",
"url": "https://up-skill.app",
"logo": "https://up-skill.app/favicon.svg",
"description": "Plataforma de cursos online para aprender nuevas habilidades con profesores expertos",
"sameAs": [
"https://www.linkedin.com/company/upskill",
"https://twitter.com/upskill"
]
};

return (
<div className="flex flex-col min-h-screen">
<Helmet>
<script type="application/ld+json">
{JSON.stringify(organizationSchema)}
</script>
</Helmet>
<NavBar />
<main className="flex-grow">
<Outlet />
Expand Down
Loading