mock index and testing rsl
This commit is contained in:
@@ -1,132 +1,396 @@
|
||||
import { Button } from "@heroui/react"
|
||||
import { Avatar, Button, Card, Chip, ScrollShadow } from "@heroui/react"
|
||||
import { createFileRoute } from "@tanstack/react-router"
|
||||
import {
|
||||
Route as RouteIcon,
|
||||
Server,
|
||||
ChevronRight,
|
||||
Cpu,
|
||||
Database,
|
||||
Euro,
|
||||
Globe,
|
||||
Layers,
|
||||
LogIn,
|
||||
Map as MapIcon,
|
||||
Radio,
|
||||
Rocket,
|
||||
Shield,
|
||||
Sparkles,
|
||||
Waves,
|
||||
Zap
|
||||
} from "lucide-react"
|
||||
import {
|
||||
Map as MapComponent,
|
||||
MapMarker,
|
||||
MarkerContent,
|
||||
MarkerPopup,
|
||||
MarkerTooltip
|
||||
} from "@/components/maps/map"
|
||||
|
||||
export const Route = createFileRoute("/")({ component: App })
|
||||
|
||||
function App() {
|
||||
const navigate = Route.useNavigate()
|
||||
const WebMockHeader = () => {
|
||||
const locations = [
|
||||
{
|
||||
id: 5,
|
||||
name: "EEUU",
|
||||
lat: 40.76,
|
||||
lng: -73.98
|
||||
},
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: <Zap className="w-12 h-12 text-cyan-400" />,
|
||||
title: "Powerful Server Functions",
|
||||
description:
|
||||
"Write server-side code that seamlessly integrates with your client components. Type-safe, secure, and simple."
|
||||
id: 1,
|
||||
name: "Madrid",
|
||||
lat: 40.4168,
|
||||
lng: -3.7038
|
||||
},
|
||||
{
|
||||
icon: <Server className="w-12 h-12 text-cyan-400" />,
|
||||
title: "Flexible Server Side Rendering",
|
||||
description:
|
||||
"Full-document SSR, streaming, and progressive enhancement out of the box. Control exactly what renders where."
|
||||
id: 2,
|
||||
name: "Barcelona",
|
||||
lat: 41.3874,
|
||||
lng: 2.1686
|
||||
},
|
||||
{
|
||||
icon: <RouteIcon className="w-12 h-12 text-cyan-400" />,
|
||||
title: "API Routes",
|
||||
description:
|
||||
"Build type-safe API endpoints alongside your application. No separate backend needed."
|
||||
id: 3,
|
||||
name: "Sevilla",
|
||||
lat: 37.3891,
|
||||
lng: -5.9845
|
||||
},
|
||||
{
|
||||
icon: <Shield className="w-12 h-12 text-cyan-400" />,
|
||||
title: "Strongly Typed Everything",
|
||||
description:
|
||||
"End-to-end type safety from server to client. Catch errors before they reach production."
|
||||
},
|
||||
{
|
||||
icon: <Waves className="w-12 h-12 text-cyan-400" />,
|
||||
title: "Full Streaming Support",
|
||||
description:
|
||||
"Stream data from server to client progressively. Perfect for AI applications and real-time updates."
|
||||
},
|
||||
{
|
||||
icon: <Sparkles className="w-12 h-12 text-cyan-400" />,
|
||||
title: "Next Generation Ready",
|
||||
description:
|
||||
"Built from the ground up for modern web applications. Deploy anywhere JavaScript runs."
|
||||
id: 4,
|
||||
name: "Valencia",
|
||||
lat: 39.4699,
|
||||
lng: -0.3763
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-linear-to-b from-slate-900 via-slate-800 to-slate-900">
|
||||
<Button
|
||||
onPress={() => {
|
||||
navigate({
|
||||
to: "/login",
|
||||
viewTransition: true
|
||||
})
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
Hola
|
||||
</Button>
|
||||
<section className="relative py-20 px-6 text-center overflow-hidden">
|
||||
<div className="absolute inset-0 bg-linear-to-r from-cyan-500/10 via-blue-500/10 to-purple-500/10"></div>
|
||||
<div className="relative max-w-5xl mx-auto">
|
||||
<div className="flex items-center justify-center gap-6 mb-6">
|
||||
<img
|
||||
src="/tanstack-circle-logo.png"
|
||||
alt="TanStack Logo"
|
||||
className="w-24 h-24 md:w-32 md:h-32"
|
||||
/>
|
||||
<h1 className="text-6xl md:text-7xl font-black text-white tracking-[-0.08em]">
|
||||
<span className="text-gray-300">TANSTACK</span>{" "}
|
||||
<span className="bg-linear-to-r from-cyan-400 to-blue-400 bg-clip-text text-transparent">
|
||||
START
|
||||
</span>
|
||||
</h1>
|
||||
</div>
|
||||
<p className="text-2xl md:text-3xl text-gray-300 mb-4 font-light">
|
||||
The framework for next generation AI applications
|
||||
<div className="space-y-6 animate-in fade-in zoom-in-95 duration-500">
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h3 className="text-xl font-black text-white tracking-tight">
|
||||
Panel de Control
|
||||
</h3>
|
||||
<p className="text-[10px] text-cyan-500 font-mono hidden">
|
||||
ID: 550e8400-e29b-41d4-a716-446655440000
|
||||
</p>
|
||||
<p className="text-lg text-gray-400 max-w-3xl mx-auto mb-8">
|
||||
Full-stack framework powered by TanStack Router for React and Solid.
|
||||
Build modern applications with server functions, streaming, and type
|
||||
safety.
|
||||
</p>
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
<a
|
||||
href="https://tanstack.com/start"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="px-8 py-3 bg-cyan-500 hover:bg-cyan-600 text-white font-semibold rounded-lg transition-colors shadow-lg shadow-cyan-500/50"
|
||||
>
|
||||
Documentation
|
||||
</a>
|
||||
<p className="text-gray-400 text-sm mt-2">
|
||||
Begin your TanStack Start journey by editing{" "}
|
||||
<code className="px-2 py-1 bg-slate-700 rounded text-cyan-400">
|
||||
/src/routes/index.tsx
|
||||
</code>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Chip size="sm" className="px-2" variant="soft">
|
||||
<div className="w-2 h-2 bg-emerald-500 rounded-full animate-pulse mr-2" />{" "}
|
||||
ACTIVO
|
||||
</Chip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{[
|
||||
{ label: "OFERTAS", val: "+300", unit: "", color: "text-white" },
|
||||
{
|
||||
label: "PILOTOS",
|
||||
val: "+400",
|
||||
unit: "",
|
||||
color: "text-gray-200/60"
|
||||
},
|
||||
{
|
||||
label: "TRAYECTOS",
|
||||
val: "+400",
|
||||
unit: "",
|
||||
color: "text-white"
|
||||
},
|
||||
{
|
||||
label: "PUESTOS",
|
||||
val: "+300",
|
||||
unit: "",
|
||||
color: "text-gray-200/60"
|
||||
}
|
||||
].map((s, i) => (
|
||||
<div key={i} className="glass p-4 rounded-2xl">
|
||||
<p className="text-[9px] text-slate-500 font-bold mb-1 tracking-widest">
|
||||
{s.label}
|
||||
</p>
|
||||
<p className={`text-xl font-black ${s.color}`}>
|
||||
{s.val}
|
||||
<span className="text-xs ml-1 opacity-50">{s.unit}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<section className="py-16 px-6 max-w-7xl mx-auto">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{features.map((feature, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="bg-slate-800/50 backdrop-blur-sm border border-slate-700 rounded-xl p-6 hover:border-cyan-500/50 transition-all duration-300 hover:shadow-lg hover:shadow-cyan-500/10"
|
||||
>
|
||||
<div className="mb-4">{feature.icon}</div>
|
||||
<h3 className="text-xl font-semibold text-white mb-3">
|
||||
{feature.title}
|
||||
</h3>
|
||||
<p className="text-gray-400 leading-relaxed">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
<div className="relative aspect-video rounded-3xl overflow-hidden group">
|
||||
<div className="absolute inset-0 bg-transparent opacity-60">
|
||||
<MapComponent
|
||||
zoom={1}
|
||||
className="min-w-xl w-full"
|
||||
center={[2.3522, 48.8566]}
|
||||
>
|
||||
{(locations || [])?.map((location) => (
|
||||
<MapMarker
|
||||
key={location.id}
|
||||
longitude={location.lng}
|
||||
latitude={location.lat}
|
||||
>
|
||||
{/* Prueba para ssl */}
|
||||
<MarkerContent>
|
||||
{/* <Drone size={24} color="green" className="text-green-200" /> */}
|
||||
<div className="w-3 h-3 bg-accent animate-pulse rounded-full" />
|
||||
</MarkerContent>
|
||||
<MarkerTooltip>{location.name}</MarkerTooltip>
|
||||
<MarkerPopup>
|
||||
<div className="space-y-1">
|
||||
<p className="font-medium text-foreground">
|
||||
{location.name}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{location.lat.toFixed(4)}, {location.lng.toFixed(4)}
|
||||
</p>
|
||||
</div>
|
||||
</MarkerPopup>
|
||||
</MapMarker>
|
||||
))}
|
||||
</MapComponent>
|
||||
</div>
|
||||
</section>
|
||||
<div className="absolute bottom-6 left-6 z-10">
|
||||
<Button>
|
||||
<MapIcon className="size-6" />
|
||||
¿Quieres ser parte de mapa?
|
||||
</Button>
|
||||
</div>
|
||||
<div className="absolute inset-0 bg-linear-to-t from-brand-dark via-transparent to-transparent"></div>
|
||||
<div className="absolute top-6 left-6 flex flex-col gap-2">
|
||||
<div className="glass p-3 rounded-xl"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function App() {
|
||||
const navigate = Route.useNavigate()
|
||||
return (
|
||||
<div className="min-h-screen bg-brand-dark text-slate-400 ">
|
||||
{/* NAVBAR */}
|
||||
<nav className="flex items-center justify-between px-10 py-6 border-b border-white/5 backdrop-blur-xl sticky top-0 z-50">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 bg-accent animate-pulse" />
|
||||
<span className="font-mono text-xs tracking-[0.3em] uppercase text-muted">
|
||||
<h1 className="text-lg font-light tracking-tighter">
|
||||
FIND<span className="font-bold text-accent">YOUR</span>PILOT
|
||||
</h1>
|
||||
</span>
|
||||
</div>
|
||||
<div className="hidden md:flex gap-8 text-[11px] font-black uppercase tracking-[0.2em]"></div>
|
||||
<Button
|
||||
onPress={() => {
|
||||
navigate({ to: "/access/login" })
|
||||
}}
|
||||
>
|
||||
Acceso <LogIn />
|
||||
</Button>
|
||||
</nav>
|
||||
|
||||
{/* HERO / LANDING */}
|
||||
<header className="relative pt-20 px-6 text-center lg:flex gap-4 pb-10">
|
||||
<div className="lg:w-2/5">
|
||||
<div className="absolute inset-0 z-0 overflow-hidden pointer-events-none">
|
||||
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-[1000px] h-[600px] bg-cyan-500/10 blur-[120px] rounded-full"></div>
|
||||
</div>
|
||||
<div className="relative z-10 max-w-5xl mx-auto">
|
||||
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-white/5 border border-white/10 text-[10px] font-black uppercase tracking-[0.3em] mb-8 text-accent">
|
||||
<Radio size={12} className="animate-pulse" />
|
||||
<span className="text-accent">v4.0.2</span>
|
||||
</div>
|
||||
|
||||
<h1 className="text-6xl md:text-6xl font-black text-white tracking-tighter mb-8 leading-[0.9]">
|
||||
ENCUENTRA A <br />
|
||||
<span className="text-transparent bg-clip-text bg-linear-to-r from-accent-400 via-accent to-stone-400 px-4">
|
||||
TU PILOTO
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p className="text-lg md:text-lg text-slate-300 max-w-2xl mx-auto mb-12 font-medium">
|
||||
La plataforma definitiva para la gestión de pilotos de drones.
|
||||
Conecta con los mejores profesionales y lleva tus proyectos al
|
||||
siguiente <span className="italic">nivel</span>.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-wrap justify-center gap-4">
|
||||
<Button size="lg">
|
||||
Iniciar despliegue <Rocket size={20} />
|
||||
</Button>
|
||||
<Button size="lg">
|
||||
Más información <ChevronRight size={20} />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="relative flex overflow-hidden group mt-20">
|
||||
<div className="flex animate-marquee whitespace-nowrap gap-16 items-center hover:paused py-2">
|
||||
{[
|
||||
{ name: "PostgreSQL", icon: <Database size={32} /> },
|
||||
{ name: "React", icon: <Layers size={32} /> },
|
||||
{ name: "Tailwind", icon: <Zap size={32} /> },
|
||||
{ name: "TanStack", icon: <Cpu size={32} /> },
|
||||
{ name: "TypeScript", icon: <Shield size={32} /> },
|
||||
{ name: "Vite", icon: <Globe size={32} /> }
|
||||
].map((logo, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center gap-4 grayscale opacity-40 hover:grayscale-0 hover:opacity-100 transition-all duration-500 cursor-pointer"
|
||||
>
|
||||
<div className="text-white">{logo.icon}</div>
|
||||
<span className="text-xl font-black italic tracking-tighter text-white uppercase">
|
||||
{logo.name}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Gradientes laterales para suavizar la entrada/salida (Fading effect) */}
|
||||
<div className="pointer-events-none absolute inset-y-0 left-0 w-20 bg-linear-to-r from-transparent to-transparent z-10"></div>
|
||||
<div className="pointer-events-none absolute inset-y-0 right-0 w-20 bg-linear-to-l from-transparent to-transparent z-10"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* DASHBOARD DEMO SECTION */}
|
||||
<section className="w-3/5 px-6 relative items-start flex ">
|
||||
<div className="max-w-5xl mx-auto w-full">
|
||||
{/* Cabecera del simulador */}
|
||||
<div className="flex items-center justify-between mb-4 px-4 hidden">
|
||||
<div className="flex gap-2">
|
||||
<div className="w-2 h-2 rounded-full bg-red-500/40" />
|
||||
<div className="w-2 h-2 rounded-full bg-orange-500/40" />
|
||||
<div className="w-2 h-2 rounded-full bg-emerald-500/40" />
|
||||
</div>
|
||||
<div className="flex items-center gap-4 text-[9px] font-mono tracking-widest text-slate-600">
|
||||
<span>BUFFER: 0ms</span>
|
||||
<span className="flex items-center gap-1 text-cyan-500/60">
|
||||
<Database size={10} /> PG_CONNECTED
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border bg-surface border-white/10 rounded shadow-[0_0_100px_rgba(6,182,212,0.05)] overflow-hidden">
|
||||
<div className="flex flex-col lg:flex-row min-h-[600px]">
|
||||
<aside className="w-full lg:max-w-82 border-r border-white/5 bg-black/40 p-8 flex flex-col gap-3">
|
||||
<Chip size="lg" variant="tertiary">
|
||||
<h3 className="text-xl font-black text-white tracking-tight">
|
||||
Ofertas
|
||||
</h3>
|
||||
</Chip>
|
||||
<ScrollShadow className="max-h-[500px]" hideScrollBar>
|
||||
<div className="flex gap-3 flex-col">
|
||||
{[
|
||||
{
|
||||
id: "J-001",
|
||||
name: "Inspección de Aerogeneradores",
|
||||
price: 1200,
|
||||
location: "Parque Eólico Tarifa",
|
||||
description:
|
||||
"Se requiere vuelo de proximidad para detección de microfisuras en palas. Obligatorio sensor térmico.",
|
||||
employer: "IberEnergía S.A.",
|
||||
tags: ["Térmico", "STS-01", "Alta Prioridad"],
|
||||
avatar: "https://i.pravatar.cc/150?u=corp1"
|
||||
},
|
||||
{
|
||||
id: "J-002",
|
||||
name: "Ortomosaico Agrícola 50Ha",
|
||||
price: 450,
|
||||
location: "Valladolid, ES",
|
||||
description:
|
||||
"Mapeo multiespectral para análisis de estrés hídrico en viñedos. Entrega en GeoJSON.",
|
||||
employer: "AgroTech Solutions",
|
||||
tags: ["Multiespectral", "Mapeo"],
|
||||
avatar: "https://i.pravatar.cc/150?u=corp2"
|
||||
},
|
||||
{
|
||||
id: "J-003",
|
||||
name: "Grabación FPVCinematic",
|
||||
price: 800,
|
||||
location: "Madrid (Circuito)",
|
||||
description:
|
||||
"Seguimiento de vehículos a alta velocidad para spot publicitario. Se requiere dron de 5 pulgadas.",
|
||||
employer: "RedMedia",
|
||||
tags: ["FPV", "ProRes"],
|
||||
avatar: "https://i.pravatar.cc/150?u=corp3"
|
||||
}
|
||||
].map((offer) => (
|
||||
<Card key={offer.id}>
|
||||
<Card.Header className="flex flex-col gap-2">
|
||||
<div className="flex gap-2">
|
||||
<Avatar size="sm">
|
||||
<Avatar.Image
|
||||
alt="John Doe"
|
||||
src={offer.avatar}
|
||||
/>
|
||||
<Avatar.Fallback>JD</Avatar.Fallback>
|
||||
</Avatar>
|
||||
<h1 className="text-md font-semibold text-start">
|
||||
{offer.name}
|
||||
</h1>
|
||||
</div>
|
||||
<ScrollShadow
|
||||
orientation="horizontal"
|
||||
className="w-[200px]"
|
||||
hideScrollBar
|
||||
>
|
||||
<div className="flex gap-2">
|
||||
{offer.tags.map((tag) => (
|
||||
<Chip variant="soft" key={tag}>
|
||||
{tag}
|
||||
</Chip>
|
||||
))}
|
||||
</div>
|
||||
</ScrollShadow>
|
||||
</Card.Header>
|
||||
<Card.Content className=" text-slate-50">
|
||||
<div className="text-xs text-start">
|
||||
{offer.description}
|
||||
</div>
|
||||
</Card.Content>
|
||||
<Card.Footer className="items-center justify-between">
|
||||
<Chip>
|
||||
{offer.price} <Euro className="size-4" />
|
||||
</Chip>
|
||||
<Button size="sm" variant="secondary">
|
||||
Detalles
|
||||
</Button>
|
||||
</Card.Footer>
|
||||
</Card>
|
||||
))}
|
||||
<div className="flex justify-end pb-10">
|
||||
<Button>Ver más</Button>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollShadow>
|
||||
</aside>
|
||||
|
||||
{/* Main Content Area */}
|
||||
<main className="flex-1 p-10 bg-linear-to-br from-transparent to-cyan-950/5">
|
||||
<WebMockHeader />
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</header>
|
||||
|
||||
{/* FOOTER TÉCNICO */}
|
||||
<footer className="border-t border-white/5 py-20 px-10">
|
||||
<div className="max-w-6xl mx-auto grid grid-cols-2 md:grid-cols-4 gap-12">
|
||||
<div>
|
||||
<p className="text-white font-black italic mb-4">FYP.OS</p>
|
||||
<p className="text-xs leading-loose">
|
||||
Gestiona tú perfil profesional, tus misiones y tus drones.
|
||||
</p>
|
||||
</div>
|
||||
{["Schema", "Security", "Endpoints"].map((title) => (
|
||||
<div key={title}>
|
||||
<p className="text-[10px] font-black text-white uppercase tracking-widest mb-4">
|
||||
{title}
|
||||
</p>
|
||||
<ul className="text-xs space-y-2 opacity-50 font-mono">
|
||||
<li>{`fetch_${title.toLowerCase()}`}</li>
|
||||
<li>{`push_logs_v4`}</li>
|
||||
<li>{`auth_verify`}</li>
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user