Files
telegram-mini-app/index.html
2025-12-27 19:35:09 +00:00

205 lines
9.2 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Telegram Mini App - Perfil de Usuario</title>
<!-- Script Oficial de Telegram WebApp -->
<script src="https://telegram.org/js/telegram-web-app.js"></script>
<!-- React y ReactDOM -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!-- Babel para JSX -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Iconos Lucide -->
<script src="https://unpkg.com/lucide@latest"></script>
<style>
body {
background-color: var(--tg-theme-bg-color, #17212b);
color: var(--tg-theme-text-color, #ffffff);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
}
</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useEffect } = React;
// Componente de Tarjeta de Información
const InfoCard = ({ icon, label, value, isLink }) => {
return (
<div className="bg-white/10 p-4 rounded-xl flex items-center justify-between mb-3 backdrop-blur-sm border border-white/5 shadow-sm">
<div className="flex items-center gap-3">
<div className="text-blue-400">
{icon}
</div>
<span className="text-gray-300 text-sm font-medium">{label}</span>
</div>
<div className="text-white font-semibold text-right truncate max-w-[150px]">
{isLink && value ? (
<span className="text-blue-400">@{value}</span>
) : (
value || "N/A"
)}
</div>
</div>
);
};
const App = () => {
const [user, setUser] = useState(null);
const [isMock, setIsMock] = useState(false);
const [themeParams, setThemeParams] = useState({});
useEffect(() => {
const tg = window.Telegram.WebApp;
// 1. Inicializar la WebApp
tg.ready();
tg.expand(); // Ocupar toda la altura disponible
// Guardar parámetros de tema para usar colores nativos si se desea
setThemeParams(tg.themeParams);
// 2. Intentar obtener el usuario
const telegramUser = tg.initDataUnsafe?.user;
if (telegramUser) {
// Estamos dentro de Telegram con un usuario real
setUser(telegramUser);
setIsMock(false);
// Configurar el color del header de Telegram para que coincida con nuestra app
tg.setHeaderColor('#1e293b'); // Un color oscuro tipo slate-800
} else {
// NO estamos en Telegram (ej: navegador web de desarrollo)
// Usamos datos falsos para visualizar el diseño
setIsMock(true);
setUser({
id: 123456789,
first_name: "Usuario",
last_name: "De Prueba",
username: "ejemplo_dev",
language_code: "es",
is_premium: true,
allows_write_to_pm: true
});
}
}, []);
// Función para renderizar iconos de Lucide (ya que estamos en CDN)
const renderIcon = (name) => {
if (!window.lucide) return null;
// Mapeo simple de iconos necesarios
const icons = {
user: <i data-lucide="user" className="w-5 h-5"></i>,
id: <i data-lucide="hash" className="w-5 h-5"></i>,
globe: <i data-lucide="globe" className="w-5 h-5"></i>,
crown: <i data-lucide="crown" className="w-5 h-5"></i>
};
return icons[name];
};
// Efecto para activar los iconos de Lucide después del renderizado
useEffect(() => {
if (window.lucide) {
window.lucide.createIcons();
}
});
if (!user) return <div className="flex justify-center items-center h-screen text-white">Cargando...</div>;
return (
<div className="min-h-screen bg-slate-900 p-4 flex flex-col items-center pt-8">
{/* Aviso si estamos en modo prueba */}
{isMock && (
<div className="w-full max-w-md bg-yellow-500/20 border border-yellow-500/50 text-yellow-200 px-4 py-2 rounded-lg mb-6 text-xs text-center">
Modo Vista Previa (Fuera de Telegram)
</div>
)}
{/* Header con Avatar */}
<div className="flex flex-col items-center mb-8 animate-fade-in-down">
<div className="relative">
<div className="w-24 h-24 bg-gradient-to-tr from-blue-500 to-purple-600 rounded-full flex items-center justify-center text-4xl font-bold text-white shadow-xl mb-4 border-4 border-slate-800">
{user.photo_url ? (
<img src={user.photo_url} alt="Profile" className="w-full h-full rounded-full object-cover" />
) : (
<span>{user.first_name?.charAt(0) || "U"}</span>
)}
</div>
{user.is_premium && (
<div className="absolute bottom-3 right-0 bg-yellow-500 text-slate-900 rounded-full p-1 border-2 border-slate-800">
<i data-lucide="star" className="w-4 h-4 fill-current"></i>
</div>
)}
</div>
<h1 className="text-2xl font-bold text-white">
{user.first_name} {user.last_name}
</h1>
{user.username && (
<p className="text-blue-400 font-medium">@{user.username}</p>
)}
</div>
{/* Lista de Datos */}
<div className="w-full max-w-md space-y-2">
<h2 className="text-slate-400 text-xs uppercase font-bold tracking-wider mb-2 ml-1">Información de Cuenta</h2>
<InfoCard
icon={<i data-lucide="hash" className="w-5 h-5"></i>}
label="ID de Telegram"
value={user.id}
/>
<InfoCard
icon={<i data-lucide="globe" className="w-5 h-5"></i>}
label="Idioma"
value={user.language_code === 'es' ? 'Español' : user.language_code?.toUpperCase()}
/>
<InfoCard
icon={<i data-lucide="zap" className="w-5 h-5"></i>}
label="Estado Premium"
value={user.is_premium ? "Activo" : "No Activo"}
/>
{/* Botón de acción */}
<button
onClick={() => window.Telegram.WebApp.close()}
className="mt-8 w-full bg-blue-600 hover:bg-blue-500 active:scale-95 transition-all text-white font-bold py-3 px-4 rounded-xl shadow-lg flex items-center justify-center gap-2"
>
<span>Cerrar Mini App</span>
</button>
</div>
{/* Raw Data (Opcional, útil para desarrollo) */}
<div className="mt-10 w-full max-w-md">
<details className="text-xs text-slate-500 cursor-pointer">
<summary className="hover:text-slate-300 transition-colors">Ver datos crudos (JSON)</summary>
<pre className="mt-2 bg-slate-950 p-3 rounded-lg overflow-x-auto text-green-400 border border-slate-800">
{JSON.stringify(user, null, 2)}
</pre>
</details>
</div>
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
</script>
</body>
</html>