Autosave: 20260501-144609
This commit is contained in:
parent
e46cec7f80
commit
ba7bba35d1
@ -90,18 +90,18 @@ export default function PublicShell({ activeSection, children, floatingAction }:
|
||||
<div className="mb-4 inline-flex items-center gap-2 rounded-full border border-[#DAA520]/40 bg-[#DAA520]/10 px-3 py-1 text-xs font-bold uppercase tracking-[0.35em] text-[#FDE68A]">
|
||||
Chinchorreo PR
|
||||
</div>
|
||||
<h1 className="text-3xl font-black tracking-tight text-white">Guía boricua para salir a chinchorrear</h1>
|
||||
<h1 className="text-3xl font-black tracking-tight text-white">La guía boricua para cuadrar un buen chinchorreo</h1>
|
||||
<p className="mt-3 text-sm leading-6 text-slate-300">
|
||||
Rutas, chinchorros, lugares y favoritos para montar la próxima ruta con sazón.
|
||||
Rutas, paradas y listas para que el próximo plan salga con sabor desde el arranque.
|
||||
</p>
|
||||
<div className="mt-5 grid grid-cols-2 gap-3 text-sm">
|
||||
<div className="rounded-2xl border border-white/10 bg-white/5 p-3">
|
||||
<div className="text-2xl font-black text-[#FDE68A]">{guideStats.routes}</div>
|
||||
<div className="text-slate-300">rutas listas</div>
|
||||
<div className="text-slate-300">rutas para salir</div>
|
||||
</div>
|
||||
<div className="rounded-2xl border border-white/10 bg-white/5 p-3">
|
||||
<div className="text-2xl font-black text-[#A7F3D0]">{guideStats.chinchorros}</div>
|
||||
<div className="text-slate-300">paradas</div>
|
||||
<div className="text-slate-300">chinchorros recomendados</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -135,7 +135,7 @@ export default function PublicShell({ activeSection, children, floatingAction }:
|
||||
<span className="mr-2">{item.emoji}</span>
|
||||
{item.label}
|
||||
</div>
|
||||
<div className="text-xs text-slate-400">Dale una vuelta</div>
|
||||
<div className="text-xs text-slate-400">Échale un ojo</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
@ -149,7 +149,7 @@ export default function PublicShell({ activeSection, children, floatingAction }:
|
||||
className="flex flex-1 items-center justify-center gap-2 rounded-2xl border border-white/10 bg-white/5 px-3 py-3 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/10"
|
||||
>
|
||||
<BaseIcon path={mdiLogin} size={18} />
|
||||
Área privada
|
||||
Iniciar sesión
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
@ -177,7 +177,7 @@ export default function PublicShell({ activeSection, children, floatingAction }:
|
||||
className="hidden items-center gap-2 rounded-full border border-white/10 bg-white/5 px-4 py-2 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/10 sm:inline-flex"
|
||||
>
|
||||
<BaseIcon path={mdiLogin} size={16} />
|
||||
Área privada
|
||||
Iniciar sesión
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@ -24,7 +24,7 @@ export default function RoutePreview({ route, compact = false }: Props) {
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
<div className="text-xs font-semibold uppercase tracking-[0.25em] text-white/80">
|
||||
Vista rápida
|
||||
De un vistazo
|
||||
</div>
|
||||
<div className="mt-1 text-lg font-black tracking-tight">{route.region}</div>
|
||||
</div>
|
||||
@ -50,8 +50,8 @@ export default function RoutePreview({ route, compact = false }: Props) {
|
||||
</div>
|
||||
|
||||
<div className="mt-5 flex items-center justify-between text-xs text-white/90">
|
||||
<span>{route.stops.length} paradas</span>
|
||||
<span>{Math.round(route.estimatedMinutes / 60)}h aprox.</span>
|
||||
<span>{route.stops.length} paradas clave</span>
|
||||
<span>{Math.round(route.estimatedMinutes / 60)} h aprox.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -156,7 +156,7 @@ export const useChinchorreoStorage = () => {
|
||||
if (!trimmedName) {
|
||||
return {
|
||||
ok: false,
|
||||
message: 'Ponle un nombre a la lista para guardarla.',
|
||||
message: 'Ponle un nombre a la lista para crearla.',
|
||||
};
|
||||
}
|
||||
|
||||
@ -179,7 +179,7 @@ export const useChinchorreoStorage = () => {
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
message: `Lista “${trimmedName}” creada y lista para usar.`,
|
||||
message: `La lista “${trimmedName}” quedó creada y activa.`,
|
||||
list: createdList,
|
||||
};
|
||||
},
|
||||
|
||||
@ -90,8 +90,8 @@ export default function EventsPage() {
|
||||
|
||||
setFeedback(
|
||||
result.added
|
||||
? `Evento guardado en “${activeList?.name || 'Mi chinchorreo'}”.`
|
||||
: 'Ese evento ya estaba en la lista activa.',
|
||||
? `Ese evento se guardó en “${activeList?.name || 'Mi chinchorreo'}”.`
|
||||
: 'Ese evento ya lo tenías en la lista activa.',
|
||||
);
|
||||
};
|
||||
|
||||
@ -106,10 +106,10 @@ export default function EventsPage() {
|
||||
<div className="max-w-3xl">
|
||||
<div className="text-xs font-bold uppercase tracking-[0.35em] text-[#FDE68A]">Eventos & Festivales</div>
|
||||
<h1 className="mt-2 text-4xl font-black tracking-tight text-white">
|
||||
Calendario sabroso entre comida, cultura y tradición
|
||||
Festivales y planes para que no se te vaya ninguno
|
||||
</h1>
|
||||
<p className="mt-3 text-base leading-7 text-slate-300">
|
||||
Aquí tienes un calendario mensual simplificado con contador regresivo y una lista de los próximos eventos más importantes del chinchorreo boricua.
|
||||
Revisa qué viene por ahí, cuándo cae y cuál vale la pena apuntar para el próximo jangueo.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@ -117,7 +117,7 @@ export default function EventsPage() {
|
||||
<input
|
||||
value={searchValue}
|
||||
onChange={(event) => setSearchValue(event.target.value)}
|
||||
placeholder="Buscar por festival, pueblo o lugar"
|
||||
placeholder="Festival, pueblo o lugar..."
|
||||
className="w-full rounded-2xl border border-white/10 bg-[#04111f]/50 px-4 py-3 text-white placeholder:text-slate-400 focus:border-[#DAA520] focus:outline-none focus:ring-0"
|
||||
/>
|
||||
</div>
|
||||
@ -134,11 +134,11 @@ export default function EventsPage() {
|
||||
<div className="rounded-[2rem] border border-white/10 bg-white/5 p-6 shadow-xl shadow-black/20">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div>
|
||||
<div className="text-xs font-bold uppercase tracking-[0.35em] text-[#FDE68A]">Mes destacado</div>
|
||||
<div className="text-xs font-bold uppercase tracking-[0.35em] text-[#FDE68A]">Mes en agenda</div>
|
||||
<h2 className="mt-2 text-3xl font-black text-white">{monthLabel(calendarMonth)}</h2>
|
||||
</div>
|
||||
<div className="rounded-full border border-white/10 bg-white/5 px-3 py-2 text-sm font-semibold text-slate-200">
|
||||
{filteredEvents.length} eventos visibles
|
||||
{filteredEvents.length} eventos en agenda
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -197,15 +197,15 @@ export default function EventsPage() {
|
||||
<div className="space-y-4 p-5">
|
||||
<div className="grid gap-3 md:grid-cols-3">
|
||||
<div className="rounded-[1.4rem] border border-white/10 bg-[#04111f]/60 p-4 text-sm text-slate-300">
|
||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-500">Fecha</div>
|
||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-500">Cuándo</div>
|
||||
<div className="mt-2 font-semibold text-white">{formatEventDate(event.nextDateIso)}</div>
|
||||
</div>
|
||||
<div className="rounded-[1.4rem] border border-white/10 bg-[#04111f]/60 p-4 text-sm text-slate-300">
|
||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-500">Lugar</div>
|
||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-500">Dónde</div>
|
||||
<div className="mt-2 font-semibold text-white">{event.venue}</div>
|
||||
</div>
|
||||
<div className="rounded-[1.4rem] border border-white/10 bg-[#04111f]/60 p-4 text-sm text-slate-300">
|
||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-500">Cuenta regresiva</div>
|
||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-500">Falta</div>
|
||||
<div className="mt-2 font-semibold text-[#FDE68A]">{getCountdownLabel(event.nextDateIso)}</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -225,7 +225,7 @@ export default function EventsPage() {
|
||||
].join(' ')}
|
||||
>
|
||||
<BaseIcon path={mdiStarOutline} size={16} />
|
||||
{saved ? 'Evento guardado' : 'Guardar evento'}
|
||||
{saved ? 'Ya guardado' : 'Guardar'}
|
||||
</button>
|
||||
<div className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-4 py-2 text-sm text-slate-200">
|
||||
<BaseIcon path={mdiCalendarStar} size={16} />
|
||||
@ -241,9 +241,9 @@ export default function EventsPage() {
|
||||
|
||||
{!filteredEvents.length ? (
|
||||
<section className="rounded-[2rem] border border-dashed border-white/15 bg-white/5 p-10 text-center shadow-xl shadow-black/20">
|
||||
<h2 className="text-2xl font-black text-white">No salió ningún evento con esa búsqueda</h2>
|
||||
<h2 className="text-2xl font-black text-white">No encontramos ningún evento con esa búsqueda</h2>
|
||||
<p className="mt-3 text-sm leading-6 text-slate-300">
|
||||
Prueba con otro pueblo o lugar, o limpia la búsqueda para ver qué viene por ahí.
|
||||
Prueba con otro pueblo o limpia la búsqueda para ver los que vienen por ahí.
|
||||
</p>
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
@ -56,7 +56,7 @@ const SectionHeader = ({
|
||||
href={href}
|
||||
className="inline-flex items-center gap-2 self-start rounded-full border border-white/10 bg-white/5 px-4 py-2 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/10"
|
||||
>
|
||||
Ver todo
|
||||
Ver más
|
||||
<BaseIcon path={mdiChevronRight} size={16} />
|
||||
</Link>
|
||||
) : null}
|
||||
@ -93,7 +93,7 @@ export default function HomePage() {
|
||||
<PublicShell
|
||||
activeSection="inicio"
|
||||
floatingAction={{
|
||||
label: 'Sorpréndeme con una ruta 🎲',
|
||||
label: 'Dame una ruta 🎲',
|
||||
icon: mdiDice5Outline,
|
||||
onClick: handleRandomRoute,
|
||||
}}
|
||||
@ -115,11 +115,10 @@ export default function HomePage() {
|
||||
¡Vamos a chinchorrear!
|
||||
</div>
|
||||
<h1 className="mt-5 text-4xl font-black tracking-tight text-white sm:text-5xl lg:text-6xl">
|
||||
Tu guía interactiva para janguear Puerto Rico con sabor, ruta y corillo.
|
||||
Tu próxima salida por Puerto Rico empieza aquí.
|
||||
</h1>
|
||||
<p className="mt-4 max-w-2xl text-base leading-7 text-slate-200 sm:text-lg">
|
||||
Explora rutas auténticas, guarda tus paradas favoritas y descubre eventos, vistas y
|
||||
chinchorros con una estética boricua vibrante y elegante.
|
||||
Encuentra rutas, guarda paradas, mira eventos y descubre chinchorros para cuadrar el plan sin tanta vuelta.
|
||||
</p>
|
||||
|
||||
<div className="relative mt-6 max-w-2xl">
|
||||
@ -130,7 +129,7 @@ export default function HomePage() {
|
||||
<input
|
||||
value={searchValue}
|
||||
onChange={(event) => setSearchValue(event.target.value)}
|
||||
placeholder="Buscar restaurante, ruta, pueblo o festival"
|
||||
placeholder="Ruta, chinchorro, pueblo o festival..."
|
||||
className="w-full border-0 bg-transparent text-base text-white placeholder:text-slate-400 focus:ring-0"
|
||||
/>
|
||||
<button
|
||||
@ -171,23 +170,23 @@ export default function HomePage() {
|
||||
className="inline-flex items-center gap-2 rounded-full bg-[#CE1126] px-5 py-3 text-sm font-bold text-white transition hover:bg-[#b90f23]"
|
||||
>
|
||||
<BaseIcon path={mdiMapMarkerPath} size={18} />
|
||||
Explorar rutas
|
||||
Ver rutas
|
||||
</Link>
|
||||
<Link
|
||||
href="/login"
|
||||
className="inline-flex items-center gap-2 rounded-full border border-white/15 bg-white/10 px-5 py-3 text-sm font-bold text-white transition hover:border-white/25 hover:bg-white/15"
|
||||
>
|
||||
<BaseIcon path={mdiLogin} size={18} />
|
||||
Área privada
|
||||
Iniciar sesión
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-4 sm:grid-cols-3 lg:grid-cols-1">
|
||||
{[
|
||||
{ label: 'Rutas curadas', value: guideStats.routes, accent: '#FDE68A' },
|
||||
{ label: 'Chinchorros destacados', value: guideStats.chinchorros, accent: '#A7F3D0' },
|
||||
{ label: 'Eventos cercanos', value: guideStats.events, accent: '#BFDBFE' },
|
||||
{ label: 'Rutas bien armadas', value: guideStats.routes, accent: '#FDE68A' },
|
||||
{ label: 'Chinchorros recomendados', value: guideStats.chinchorros, accent: '#A7F3D0' },
|
||||
{ label: 'Eventos por venir', value: guideStats.events, accent: '#BFDBFE' },
|
||||
].map((stat) => (
|
||||
<div
|
||||
key={stat.label}
|
||||
@ -199,7 +198,7 @@ export default function HomePage() {
|
||||
<div className="mt-3 text-4xl font-black tracking-tight" style={{ color: stat.accent }}>
|
||||
{stat.value}
|
||||
</div>
|
||||
<div className="mt-2 text-sm text-slate-200">Listas para descubrir hoy mismo.</div>
|
||||
<div className="mt-2 text-sm text-slate-200">Buenas para arrancar hoy mismo.</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@ -285,7 +284,7 @@ export default function HomePage() {
|
||||
href={`/restaurantes?search=${encodeURIComponent(stop.name)}`}
|
||||
className="inline-flex items-center gap-2 text-sm font-semibold text-[#FDE68A]"
|
||||
>
|
||||
Ver en la guía
|
||||
Abrir en la guía
|
||||
<BaseIcon path={mdiChevronRight} size={16} />
|
||||
</Link>
|
||||
</div>
|
||||
@ -322,7 +321,7 @@ export default function HomePage() {
|
||||
</div>
|
||||
<div className="mt-4 inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-3 py-2 text-xs font-semibold text-slate-200">
|
||||
<BaseIcon path={mdiWeatherPartlyCloudy} size={16} />
|
||||
Ideal para ruta mixta de costa y montaña
|
||||
Buen día para mezclar costa y montaña
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -340,7 +339,7 @@ export default function HomePage() {
|
||||
href="/tips"
|
||||
className="mt-4 inline-flex items-center gap-2 text-sm font-semibold text-[#A7F3D0]"
|
||||
>
|
||||
Ver guía completa
|
||||
Ver tips
|
||||
<BaseIcon path={mdiChevronRight} size={16} />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@ -53,45 +53,44 @@ export default function PlacesPage() {
|
||||
|
||||
setFeedback(
|
||||
result.added
|
||||
? `Lugar guardado en “${activeList?.name || 'Mi chinchorreo'}”.`
|
||||
: 'Ese lugar ya estaba en la lista activa.',
|
||||
? `Ese lugar se guardó en “${activeList?.name || 'Mi chinchorreo'}”.`
|
||||
: 'Ese lugar ya lo tenías en la lista activa.',
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Chinchorreo PR | Lugares de Interés</title>
|
||||
<title>Chinchorreo PR | Lugares</title>
|
||||
</Head>
|
||||
|
||||
<PublicShell activeSection="lugares">
|
||||
<section className="rounded-[2rem] border border-white/10 bg-white/5 p-6 shadow-xl shadow-black/20 sm:p-8">
|
||||
<div className="max-w-3xl">
|
||||
<div className="text-xs font-bold uppercase tracking-[0.35em] text-[#FDE68A]">Lugares de interés</div>
|
||||
<div className="text-xs font-bold uppercase tracking-[0.35em] text-[#FDE68A]">Lugares</div>
|
||||
<h1 className="mt-2 text-4xl font-black tracking-tight text-white">
|
||||
Playas, miradores, pueblos y cultura para completar la ruta
|
||||
Playas, miradores y pueblos que le suman al plan
|
||||
</h1>
|
||||
<p className="mt-3 text-base leading-7 text-slate-300">
|
||||
Usa estos lugares como pausas estratégicas entre paradas gastronómicas: fotos, vistas,
|
||||
artesanías o una caminata corta para seguir con el plan.
|
||||
Aquí encuentras paradas buenas para sacar fotos, coger aire o meterle una vista brutal antes de seguir.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 grid gap-4 rounded-[1.8rem] border border-white/10 bg-[#04111f]/50 p-4 md:grid-cols-[2fr_1fr]">
|
||||
<label className="block">
|
||||
<div className="mb-2 text-xs font-semibold uppercase tracking-[0.25em] text-slate-400">
|
||||
Buscar lugar
|
||||
Busca un lugar
|
||||
</div>
|
||||
<input
|
||||
value={searchValue}
|
||||
onChange={(event) => setSearchValue(event.target.value)}
|
||||
placeholder="Loíza, playa, mirador, cultura..."
|
||||
placeholder="Pueblo, playa, mirador o plan cultural..."
|
||||
className="w-full rounded-2xl border border-white/10 bg-white/5 px-4 py-3 text-white placeholder:text-slate-400 focus:border-[#DAA520] focus:outline-none focus:ring-0"
|
||||
/>
|
||||
</label>
|
||||
<label className="block">
|
||||
<div className="mb-2 text-xs font-semibold uppercase tracking-[0.25em] text-slate-400">
|
||||
Categoría
|
||||
Tipo de lugar
|
||||
</div>
|
||||
<select
|
||||
value={selectedCategory}
|
||||
@ -109,7 +108,7 @@ export default function PlacesPage() {
|
||||
|
||||
<div className="mt-4 flex flex-wrap items-center gap-3 text-sm text-slate-300">
|
||||
<div className="rounded-full border border-white/10 bg-white/5 px-4 py-2">
|
||||
{filteredPlaces.length} lugares disponibles
|
||||
{filteredPlaces.length} paradas para explorar
|
||||
</div>
|
||||
{feedback ? (
|
||||
<div className="inline-flex items-center gap-2 rounded-full border border-[#228B22]/30 bg-[#228B22]/10 px-4 py-2 text-[#A7F3D0]">
|
||||
@ -122,9 +121,9 @@ export default function PlacesPage() {
|
||||
|
||||
{!filteredPlaces.length ? (
|
||||
<section className="rounded-[2rem] border border-dashed border-white/15 bg-white/5 p-10 text-center shadow-xl shadow-black/20">
|
||||
<h2 className="text-2xl font-black text-white">Con esos filtros no salió ningún lugar</h2>
|
||||
<h2 className="text-2xl font-black text-white">No encontramos ningún lugar con esos filtros</h2>
|
||||
<p className="mt-3 text-sm leading-6 text-slate-300">
|
||||
Prueba otro pueblo, cambia la categoría o borra la búsqueda para seguir explorando.
|
||||
Prueba otro pueblo, cambia el tipo de lugar o borra la búsqueda para seguir mirando.
|
||||
</p>
|
||||
</section>
|
||||
) : null}
|
||||
@ -152,11 +151,11 @@ export default function PlacesPage() {
|
||||
<div className="space-y-4 p-5">
|
||||
<p className="text-sm leading-6 text-slate-300">{place.description}</p>
|
||||
<div className="rounded-[1.4rem] border border-white/10 bg-[#04111f]/60 p-4 text-sm text-slate-300">
|
||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-500">Mejor horario</div>
|
||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-500">Cuándo ir</div>
|
||||
<div className="mt-2 font-semibold text-white">{place.bestTime}</div>
|
||||
</div>
|
||||
<div className="rounded-[1.4rem] border border-white/10 bg-[#04111f]/60 p-4 text-sm text-slate-300">
|
||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-500">Consejo local</div>
|
||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-500">Dato local</div>
|
||||
<div className="mt-2 leading-6 text-white">{place.localTip}</div>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
@ -167,7 +166,7 @@ export default function PlacesPage() {
|
||||
className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-4 py-2 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/10"
|
||||
>
|
||||
<BaseIcon path={mdiCompassOutline} size={16} />
|
||||
Cómo llegar
|
||||
Abrir en Maps
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
@ -180,7 +179,7 @@ export default function PlacesPage() {
|
||||
].join(' ')}
|
||||
>
|
||||
<BaseIcon path={mdiStarOutline} size={16} />
|
||||
{saved ? 'Lugar guardado' : 'Guardar lugar'}
|
||||
{saved ? 'Ya guardado' : 'Guardar'}
|
||||
</button>
|
||||
</div>
|
||||
<div className="inline-flex items-center gap-2 text-sm text-slate-300">
|
||||
|
||||
@ -118,27 +118,27 @@ export default function MapPage() {
|
||||
<div className="max-w-3xl">
|
||||
<div className="text-xs font-bold uppercase tracking-[0.35em] text-[#FDE68A]">Mapa interactivo</div>
|
||||
<h1 className="mt-2 text-4xl font-black tracking-tight text-white">
|
||||
Un mapa estilizado para descubrir paradas por categoría
|
||||
Mira todo en mapa y arma la ruta a tu manera
|
||||
</h1>
|
||||
<p className="mt-3 text-base leading-7 text-slate-300">
|
||||
Esta primera versión te deja alternar entre mapa y lista, filtrar categorías y trazar una mini ruta con los pins que selecciones.
|
||||
Explora por mapa o por lista, filtra lo que quieres ver y marca las paradas que te llamen.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 grid gap-4 rounded-[1.8rem] border border-white/10 bg-[#04111f]/50 p-4 md:grid-cols-[2fr_1fr_1fr] lg:grid-cols-[2fr_1fr_1fr_1fr]">
|
||||
<label className="block md:col-span-1 lg:col-span-2">
|
||||
<div className="mb-2 text-xs font-semibold uppercase tracking-[0.25em] text-slate-400">
|
||||
Buscar pin
|
||||
Busca una parada
|
||||
</div>
|
||||
<input
|
||||
value={searchValue}
|
||||
onChange={(event) => setSearchValue(event.target.value)}
|
||||
placeholder="Piñones, Loíza, Luquillo, cultura..."
|
||||
placeholder="Pueblo, parada, chinchorro o plan cultural..."
|
||||
className="w-full rounded-2xl border border-white/10 bg-white/5 px-4 py-3 text-white placeholder:text-slate-400 focus:border-[#DAA520] focus:outline-none focus:ring-0"
|
||||
/>
|
||||
</label>
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="text-xs font-semibold uppercase tracking-[0.25em] text-slate-400">Categorías</div>
|
||||
<div className="text-xs font-semibold uppercase tracking-[0.25em] text-slate-400">Qué quieres ver</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowChinchorros((current) => !current)}
|
||||
@ -165,7 +165,7 @@ export default function MapPage() {
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="text-xs font-semibold uppercase tracking-[0.25em] text-slate-400">Vista</div>
|
||||
<div className="text-xs font-semibold uppercase tracking-[0.25em] text-slate-400">Cómo verlo</div>
|
||||
{(['mapa', 'lista'] as MapViewMode[]).map((viewMode) => (
|
||||
<button
|
||||
key={viewMode}
|
||||
@ -227,9 +227,9 @@ export default function MapPage() {
|
||||
<div className="absolute bottom-6 left-6 rounded-[1.6rem] border border-white/10 bg-[#04111f]/70 p-4 text-sm text-slate-200 backdrop-blur">
|
||||
<div className="inline-flex items-center gap-2 text-[#FDE68A]">
|
||||
<BaseIcon path={mdiMapLegend} size={16} />
|
||||
Selecciona un pin para ver detalle
|
||||
Toca una parada para verla mejor
|
||||
</div>
|
||||
<div className="mt-2">Usa “Agregar a la ruta” para conectar varios puntos.</div>
|
||||
<div className="mt-2">Si te gusta una, súmala con “Sumar a la ruta”.</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
@ -263,7 +263,7 @@ export default function MapPage() {
|
||||
: 'border-white/10 bg-white/5 text-white hover:border-white/20 hover:bg-white/10',
|
||||
].join(' ')}
|
||||
>
|
||||
{inRoute ? 'Quitar de la ruta' : 'Agregar a la ruta'}
|
||||
{inRoute ? 'Sacar de la ruta' : 'Sumar a la ruta'}
|
||||
</button>
|
||||
</article>
|
||||
);
|
||||
@ -297,7 +297,7 @@ export default function MapPage() {
|
||||
href={selectedItem.href}
|
||||
className="inline-flex items-center gap-2 rounded-full bg-white px-4 py-2 text-sm font-semibold text-[#04111f]"
|
||||
>
|
||||
Ver en la guía
|
||||
Abrir en la guía
|
||||
<BaseIcon path={mdiChevronRight} size={16} />
|
||||
</Link>
|
||||
<a
|
||||
@ -307,7 +307,7 @@ export default function MapPage() {
|
||||
className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-4 py-2 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/10"
|
||||
>
|
||||
<BaseIcon path={mdiCompassOutline} size={16} />
|
||||
Google Maps
|
||||
Abrir en Maps
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
@ -320,8 +320,8 @@ export default function MapPage() {
|
||||
].join(' ')}
|
||||
>
|
||||
{routeSelection.includes(selectedItem.id)
|
||||
? 'Quitar de la ruta'
|
||||
: 'Agregar a la ruta'}
|
||||
? 'Sacar de la ruta'
|
||||
: 'Sumar a la ruta'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -350,14 +350,14 @@ export default function MapPage() {
|
||||
className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-3 py-2 text-xs font-semibold text-slate-200"
|
||||
>
|
||||
<BaseIcon path={mdiCloseCircleOutline} size={14} />
|
||||
Quitar
|
||||
Sacar
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-5 rounded-[1.6rem] border border-dashed border-white/10 bg-[#04111f]/40 p-5 text-sm leading-6 text-slate-300">
|
||||
Marca varias paradas para armar una mini ruta. Con dos o más ya puedes abrirla.
|
||||
Suma varias paradas y aquí se te arma la mini ruta. Con dos o más ya la puedes abrir.
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -369,7 +369,7 @@ export default function MapPage() {
|
||||
className="mt-5 inline-flex items-center gap-2 rounded-full bg-white px-5 py-3 text-sm font-bold text-[#04111f]"
|
||||
>
|
||||
<BaseIcon path={mdiMapSearchOutline} size={16} />
|
||||
Abrir ruta
|
||||
Abrir en Maps
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
@ -378,9 +378,9 @@ export default function MapPage() {
|
||||
|
||||
{!visibleItems.length ? (
|
||||
<section className="rounded-[2rem] border border-dashed border-white/15 bg-white/5 p-10 text-center shadow-xl shadow-black/20">
|
||||
<h2 className="text-2xl font-black text-white">Con esos filtros no se ve ninguna parada en el mapa</h2>
|
||||
<h2 className="text-2xl font-black text-white">No encontramos paradas con esos filtros</h2>
|
||||
<p className="mt-3 text-sm leading-6 text-slate-300">
|
||||
Vuelve a activar chinchorros o lugares, o limpia la búsqueda para verlo completo otra vez.
|
||||
Activa otra vez chinchorros o lugares, o limpia la búsqueda para verlo completo.
|
||||
</p>
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
@ -21,7 +21,7 @@ import LayoutGuest from '../layouts/Guest';
|
||||
|
||||
const categoryLabels: Record<FavoriteCategory, string> = {
|
||||
route: 'Rutas',
|
||||
chinchorro: 'Restaurantes',
|
||||
chinchorro: 'Chinchorros',
|
||||
place: 'Lugares',
|
||||
event: 'Eventos',
|
||||
};
|
||||
@ -73,7 +73,7 @@ export default function FavoritesPage() {
|
||||
|
||||
const shareList = () => {
|
||||
if (!activeFavorites.length) {
|
||||
setFeedback('Agrega al menos una ruta o chinchorro antes de compartir la lista.');
|
||||
setFeedback('Guarda aunque sea una parada antes de compartir esta lista.');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -91,52 +91,51 @@ export default function FavoritesPage() {
|
||||
|
||||
const handleRemoveFavorite = (category: FavoriteCategory, itemSlug: string) => {
|
||||
removeFavorite(category, itemSlug, activeListId);
|
||||
setFeedback('Se quitó de la lista activa.');
|
||||
setFeedback('Lo saqué de esta lista.');
|
||||
};
|
||||
|
||||
const handleRemoveList = () => {
|
||||
const removed = removeList(activeListId);
|
||||
setFeedback(
|
||||
removed
|
||||
? 'La lista personalizada fue eliminada.'
|
||||
: 'La lista principal “Mi chinchorreo” no se puede eliminar.',
|
||||
? 'Lista borrada.'
|
||||
: '“Mi chinchorreo” es la lista principal y no se puede borrar.',
|
||||
);
|
||||
};
|
||||
|
||||
const handleClearList = () => {
|
||||
clearListFavorites(activeListId);
|
||||
setFeedback('Se vació la lista activa, pero la lista sigue creada.');
|
||||
setFeedback('La lista quedó vacía, pero sigue ahí.');
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Chinchorreo PR | Mis Favoritos</title>
|
||||
<title>Chinchorreo PR | Favoritos</title>
|
||||
</Head>
|
||||
|
||||
<PublicShell activeSection="favoritos">
|
||||
<section className="grid gap-6 xl:grid-cols-[1fr_1fr]">
|
||||
<div className="rounded-[2rem] border border-white/10 bg-white/5 p-6 shadow-xl shadow-black/20 sm:p-8">
|
||||
<div className="text-xs font-bold uppercase tracking-[0.35em] text-[#FDE68A]">Mis Favoritos</div>
|
||||
<div className="text-xs font-bold uppercase tracking-[0.35em] text-[#FDE68A]">Favoritos</div>
|
||||
<h1 className="mt-2 text-4xl font-black tracking-tight text-white">
|
||||
Crea listas y guarda tus próximos jangueos
|
||||
Guarda ideas para el próximo chinchorreo
|
||||
</h1>
|
||||
<p className="mt-3 text-base leading-7 text-slate-300">
|
||||
Tus favoritos se guardan en este dispositivo: puedes crear listas,
|
||||
elegir una lista activa y compartirla por WhatsApp.
|
||||
Arma listas por plan, deja una activa y comparte por WhatsApp lo que ya vas cuadrando.
|
||||
</p>
|
||||
|
||||
<div className="mt-6 grid gap-4 sm:grid-cols-3">
|
||||
<div className="rounded-[1.7rem] border border-white/10 bg-[#04111f]/60 p-4">
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Listas</div>
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Tus listas</div>
|
||||
<div className="mt-2 text-3xl font-black text-white">{lists.length}</div>
|
||||
</div>
|
||||
<div className="rounded-[1.7rem] border border-white/10 bg-[#04111f]/60 p-4">
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Activa</div>
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Lista activa</div>
|
||||
<div className="mt-2 text-xl font-black text-[#FDE68A]">{activeList?.name}</div>
|
||||
</div>
|
||||
<div className="rounded-[1.7rem] border border-white/10 bg-[#04111f]/60 p-4">
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Guardados</div>
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">En esta lista</div>
|
||||
<div className="mt-2 text-3xl font-black text-white">{activeFavorites.length}</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -185,7 +184,7 @@ export default function FavoritesPage() {
|
||||
type="submit"
|
||||
className="inline-flex items-center gap-2 rounded-full bg-white px-5 py-3 text-sm font-bold text-[#04111f]"
|
||||
>
|
||||
Crear lista
|
||||
Crear esta lista
|
||||
<BaseIcon path={mdiChevronRight} size={16} />
|
||||
</button>
|
||||
</div>
|
||||
@ -205,14 +204,14 @@ export default function FavoritesPage() {
|
||||
className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-4 py-2 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/10"
|
||||
>
|
||||
<BaseIcon path={mdiShareVariantOutline} size={16} />
|
||||
Compartir lista
|
||||
Compartir por WhatsApp
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleClearList}
|
||||
className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-transparent px-4 py-2 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/5"
|
||||
>
|
||||
Vaciar esta lista
|
||||
Dejarla vacía
|
||||
</button>
|
||||
{activeListId !== DEFAULT_PUBLIC_LIST_ID ? (
|
||||
<button
|
||||
@ -220,7 +219,7 @@ export default function FavoritesPage() {
|
||||
onClick={handleRemoveList}
|
||||
className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-transparent px-4 py-2 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/5"
|
||||
>
|
||||
Eliminar lista
|
||||
Borrar lista
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
@ -242,12 +241,12 @@ export default function FavoritesPage() {
|
||||
].join(' ')}
|
||||
>
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">
|
||||
{isActive ? 'Lista activa' : 'Usar esta lista'}
|
||||
{isActive ? 'La que estás usando' : 'Usar esta'}
|
||||
</div>
|
||||
<h3 className="mt-2 text-2xl font-black text-white">{list.name}</h3>
|
||||
<p className="mt-2 text-sm leading-6 text-slate-300">{list.description}</p>
|
||||
<div className="mt-4 text-sm text-slate-400">
|
||||
{(favoritesByList[list.id] || []).length} guardados
|
||||
{(favoritesByList[list.id] || []).length} guardados aquí
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
@ -268,7 +267,7 @@ export default function FavoritesPage() {
|
||||
<div className={`text-xs font-bold uppercase tracking-[0.35em] ${categoryAccents[category]}`}>
|
||||
{categoryLabels[category]}
|
||||
</div>
|
||||
<h2 className="mt-2 text-2xl font-black text-white">{items.length} guardados</h2>
|
||||
<h2 className="mt-2 text-2xl font-black text-white">{items.length} en esta categoría</h2>
|
||||
</div>
|
||||
<div className="rounded-full border border-white/10 bg-white/5 px-3 py-2 text-sm font-semibold text-slate-200">
|
||||
{categoryLabels[category]}
|
||||
@ -296,7 +295,7 @@ export default function FavoritesPage() {
|
||||
href={item.itemHref}
|
||||
className="inline-flex items-center gap-2 rounded-full bg-white px-4 py-2 text-sm font-semibold text-[#04111f]"
|
||||
>
|
||||
Ver en la guía
|
||||
Abrir en la guía
|
||||
<BaseIcon path={mdiChevronRight} size={16} />
|
||||
</Link>
|
||||
<button
|
||||
@ -305,7 +304,7 @@ export default function FavoritesPage() {
|
||||
className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-transparent px-4 py-2 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/5"
|
||||
>
|
||||
<BaseIcon path={mdiCloseCircleOutline} size={16} />
|
||||
Quitar
|
||||
Sacar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -313,7 +312,7 @@ export default function FavoritesPage() {
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-5 rounded-[1.6rem] border border-dashed border-white/10 bg-[#04111f]/40 p-6 text-sm leading-6 text-slate-300">
|
||||
Aquí todavía no has guardado {categoryLabels[category].toLowerCase()} en esta lista.
|
||||
Todavía no has guardado {categoryLabels[category].toLowerCase()} en esta lista.
|
||||
</div>
|
||||
)}
|
||||
</article>
|
||||
@ -324,7 +323,7 @@ export default function FavoritesPage() {
|
||||
{!activeFavorites.length ? (
|
||||
<section className="rounded-[2rem] border border-dashed border-white/15 bg-white/5 p-10 text-center shadow-xl shadow-black/20">
|
||||
<BaseIcon path={mdiStarOutline} size={42} className="mx-auto text-[#FDE68A]" />
|
||||
<h2 className="mt-4 text-3xl font-black text-white">Esta lista está vacía por ahora</h2>
|
||||
<h2 className="mt-4 text-3xl font-black text-white">Todavía no hay nada en esta lista</h2>
|
||||
<p className="mt-3 text-sm leading-6 text-slate-300">
|
||||
Guarda una ruta, un chinchorro o un lugar desde la guía y aquí se te irá armando el plan.
|
||||
</p>
|
||||
@ -333,13 +332,13 @@ export default function FavoritesPage() {
|
||||
href="/rutas"
|
||||
className="rounded-full bg-white px-5 py-3 text-sm font-bold text-[#04111f]"
|
||||
>
|
||||
Explorar rutas
|
||||
Ir a rutas
|
||||
</Link>
|
||||
<Link
|
||||
href="/restaurantes"
|
||||
className="rounded-full border border-white/10 bg-white/5 px-5 py-3 text-sm font-bold text-white"
|
||||
>
|
||||
Ver chinchorros
|
||||
Ir a chinchorros
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -90,15 +90,15 @@ export default function RestaurantsPage() {
|
||||
|
||||
setFeedback(
|
||||
result.added
|
||||
? `Chinchorro guardado en “${activeList?.name || 'Mi chinchorreo'}”.`
|
||||
: 'Ese chinchorro ya estaba en la lista activa.',
|
||||
? `Ese chinchorro se guardó en “${activeList?.name || 'Mi chinchorreo'}”.`
|
||||
: 'Ese chinchorro ya lo tenías en la lista activa.',
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Chinchorreo PR | Restaurantes & Chinchorros</title>
|
||||
<title>Chinchorreo PR | Chinchorros</title>
|
||||
</Head>
|
||||
|
||||
<PublicShell activeSection="restaurantes">
|
||||
@ -106,14 +106,13 @@ export default function RestaurantsPage() {
|
||||
<div className="flex flex-col gap-6 lg:flex-row lg:items-end lg:justify-between">
|
||||
<div className="max-w-3xl">
|
||||
<div className="text-xs font-bold uppercase tracking-[0.35em] text-[#FDE68A]">
|
||||
Restaurantes & Chinchorros
|
||||
Chinchorros
|
||||
</div>
|
||||
<h1 className="mt-2 text-4xl font-black tracking-tight text-white">
|
||||
Filtra por región, ambiente y antojo
|
||||
Encuentra un chinchorro según el antojo y el ambiente
|
||||
</h1>
|
||||
<p className="mt-3 text-base leading-7 text-slate-300">
|
||||
Desde Piñones hasta La Parguera, aquí tienes una lista buscable con especialidades,
|
||||
redes, mapas y favoritos guardados localmente.
|
||||
Desde Piñones hasta La Parguera, aquí buscas por zona, ambiente o antojo y guardas los chinchorros que quieres repetir.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
@ -134,25 +133,25 @@ export default function RestaurantsPage() {
|
||||
<div className="mt-6 grid gap-4 rounded-[1.8rem] border border-white/10 bg-[#04111f]/50 p-4 md:grid-cols-2 xl:grid-cols-5">
|
||||
<label className="block xl:col-span-2">
|
||||
<div className="mb-2 text-xs font-semibold uppercase tracking-[0.25em] text-slate-400">
|
||||
Buscar
|
||||
Busca un chinchorro
|
||||
</div>
|
||||
<input
|
||||
value={searchValue}
|
||||
onChange={(event) => setSearchValue(event.target.value)}
|
||||
placeholder="Piñones, lechonera, longaniza, Luquillo..."
|
||||
placeholder="Piñones, lechonera, fritura o Luquillo..."
|
||||
className="w-full rounded-2xl border border-white/10 bg-white/5 px-4 py-3 text-white placeholder:text-slate-400 focus:border-[#DAA520] focus:outline-none focus:ring-0"
|
||||
/>
|
||||
</label>
|
||||
|
||||
{[
|
||||
{
|
||||
title: 'Región',
|
||||
title: 'Zona',
|
||||
value: selectedRegion,
|
||||
options: ['Todas', ...regionOptions],
|
||||
onChange: setSelectedRegion,
|
||||
},
|
||||
{
|
||||
title: 'Tipo',
|
||||
title: 'Tipo de chinchorro',
|
||||
value: selectedType,
|
||||
options: ['Todas', ...typeOptions],
|
||||
onChange: setSelectedType,
|
||||
@ -164,7 +163,7 @@ export default function RestaurantsPage() {
|
||||
onChange: setSelectedVibe,
|
||||
},
|
||||
{
|
||||
title: 'Precio',
|
||||
title: 'Presupuesto',
|
||||
value: selectedPrice,
|
||||
options: ['Todas', ...priceOptions],
|
||||
onChange: setSelectedPrice,
|
||||
@ -200,10 +199,10 @@ export default function RestaurantsPage() {
|
||||
: 'border-white/10 bg-white/5 text-white hover:border-white/20 hover:bg-white/10',
|
||||
].join(' ')}
|
||||
>
|
||||
Abierto ahora {openNowOnly ? '✓' : ''}
|
||||
Solo abiertos ahora {openNowOnly ? '✓' : ''}
|
||||
</button>
|
||||
<div className="rounded-full border border-white/10 bg-white/5 px-4 py-2">
|
||||
{filteredChinchorros.length} chinchorros encontrados
|
||||
{filteredChinchorros.length} chinchorros para este plan
|
||||
</div>
|
||||
{feedback ? (
|
||||
<div className="inline-flex items-center gap-2 rounded-full border border-[#228B22]/30 bg-[#228B22]/10 px-4 py-2 text-[#A7F3D0]">
|
||||
@ -261,26 +260,26 @@ export default function RestaurantsPage() {
|
||||
: 'border-white/10 bg-white/5 text-slate-300',
|
||||
].join(' ')}
|
||||
>
|
||||
{chinchorro.openNow ? 'Abierto ahora' : 'Abre luego'}
|
||||
{chinchorro.openNow ? 'Abierto ahora' : 'Cerrado ahora'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
<div className="rounded-[1.4rem] border border-white/10 bg-[#04111f]/60 p-4 text-sm text-slate-300">
|
||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-500">Dirección</div>
|
||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-500">Dónde queda</div>
|
||||
<div className="mt-2 flex items-start gap-2 text-white">
|
||||
<BaseIcon path={mdiMapMarker} size={16} className="mt-0.5" />
|
||||
<span>{chinchorro.address}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-[1.4rem] border border-white/10 bg-[#04111f]/60 p-4 text-sm text-slate-300">
|
||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-500">Horario</div>
|
||||
<div className="text-xs uppercase tracking-[0.2em] text-slate-500">Cuándo ir</div>
|
||||
<div className="mt-2 text-white">{chinchorro.hours}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-xs font-semibold uppercase tracking-[0.25em] text-slate-400">Especialidades</div>
|
||||
<div className="text-xs font-semibold uppercase tracking-[0.25em] text-slate-400">Qué pedir</div>
|
||||
<div className="mt-3 flex flex-wrap gap-2">
|
||||
{chinchorro.specialties.map((specialty) => (
|
||||
<span
|
||||
@ -294,7 +293,7 @@ export default function RestaurantsPage() {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="text-xs font-semibold uppercase tracking-[0.25em] text-slate-400">Galería de platos</div>
|
||||
<div className="text-xs font-semibold uppercase tracking-[0.25em] text-slate-400">Se antoja pedir</div>
|
||||
<div className="mt-3 grid gap-3 sm:grid-cols-3">
|
||||
{chinchorro.dishGallery.map((dish) => (
|
||||
<div
|
||||
@ -353,7 +352,7 @@ export default function RestaurantsPage() {
|
||||
className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-4 py-2 text-sm font-semibold text-white transition hover:border-white/20 hover:bg-white/10"
|
||||
>
|
||||
<BaseIcon path={mdiOpenInNew} size={16} />
|
||||
Google Maps
|
||||
Abrir en Maps
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
@ -373,14 +372,14 @@ export default function RestaurantsPage() {
|
||||
].join(' ')}
|
||||
>
|
||||
<BaseIcon path={mdiStarOutline} size={16} />
|
||||
{saved ? 'Chinchorro guardado' : 'Guardar chinchorro'}
|
||||
{saved ? 'Ya guardado' : 'Guardar'}
|
||||
</button>
|
||||
{chinchorro.routeSlug ? (
|
||||
<Link
|
||||
href={`/rutas/${chinchorro.routeSlug}`}
|
||||
className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-transparent px-4 py-2 text-sm font-semibold text-slate-200 transition hover:border-white/20 hover:bg-white/5"
|
||||
>
|
||||
Ver ruta
|
||||
Abrir ruta
|
||||
<BaseIcon path={mdiChevronRight} size={16} />
|
||||
</Link>
|
||||
) : null}
|
||||
@ -393,9 +392,9 @@ export default function RestaurantsPage() {
|
||||
|
||||
{!filteredChinchorros.length ? (
|
||||
<section className="rounded-[2rem] border border-dashed border-white/15 bg-white/5 p-10 text-center shadow-xl shadow-black/20">
|
||||
<h2 className="text-2xl font-black text-white">Con esos filtros no salió ningún chinchorro</h2>
|
||||
<h2 className="text-2xl font-black text-white">No encontramos ningún chinchorro con esos filtros</h2>
|
||||
<p className="mt-3 text-sm leading-6 text-slate-300">
|
||||
Prueba otro pueblo, quita “Abierto ahora” o cambia la región para ver más opciones.
|
||||
Prueba otra zona, cambia el presupuesto o quita “Solo abiertos ahora”.
|
||||
</p>
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
@ -61,7 +61,7 @@ export default function RouteDetailPage() {
|
||||
href="/rutas"
|
||||
className="mt-5 inline-flex items-center gap-2 rounded-full bg-white px-5 py-3 text-sm font-bold text-[#04111f]"
|
||||
>
|
||||
Volver a rutas
|
||||
Regresar a rutas
|
||||
<BaseIcon path={mdiChevronRight} size={16} />
|
||||
</Link>
|
||||
</section>
|
||||
@ -85,14 +85,14 @@ export default function RouteDetailPage() {
|
||||
|
||||
setFeedback(
|
||||
result.added
|
||||
? `Ruta guardada en “${activeList?.name || 'Mi chinchorreo'}”.`
|
||||
: 'Esta ruta ya está guardada en tu lista activa.',
|
||||
? `Esa ruta se guardó en “${activeList?.name || 'Mi chinchorreo'}”.`
|
||||
: 'Esa ruta ya estaba en tu lista activa.',
|
||||
);
|
||||
};
|
||||
|
||||
const handleToggleStop = (stopId: string) => {
|
||||
const result = toggleRouteStop(route.slug, stopId);
|
||||
setFeedback(result.completed ? 'Parada marcada como completada ✅' : 'Parada marcada como pendiente.');
|
||||
setFeedback(result.completed ? 'Parada marcada como hecha ✅' : 'La parada volvió a quedar pendiente.');
|
||||
};
|
||||
|
||||
return (
|
||||
@ -114,7 +114,7 @@ export default function RouteDetailPage() {
|
||||
<div className="relative grid gap-8 lg:grid-cols-[1.05fr_0.95fr] lg:items-end">
|
||||
<div>
|
||||
<Link href="/rutas" className="inline-flex items-center gap-2 text-sm font-semibold text-slate-200">
|
||||
← Volver a rutas
|
||||
← Regresar a rutas
|
||||
</Link>
|
||||
<div className="mt-4 inline-flex items-center gap-2 rounded-full border border-white/15 bg-white/10 px-4 py-2 text-xs font-bold uppercase tracking-[0.35em] text-[#FDE68A]">
|
||||
{route.emoji} {route.region}
|
||||
@ -143,7 +143,7 @@ export default function RouteDetailPage() {
|
||||
className="inline-flex items-center gap-2 rounded-full bg-white px-5 py-3 text-sm font-bold text-[#04111f] transition hover:bg-slate-100"
|
||||
>
|
||||
<BaseIcon path={mdiCompassOutline} size={16} />
|
||||
Abrir navegación
|
||||
Abrir en Maps
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
@ -156,7 +156,7 @@ export default function RouteDetailPage() {
|
||||
].join(' ')}
|
||||
>
|
||||
<BaseIcon path={mdiStarOutline} size={16} />
|
||||
{saved ? 'Ruta guardada' : 'Guardar ruta'}
|
||||
{saved ? 'Ya guardada' : 'Guardar'}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@ -164,7 +164,7 @@ export default function RouteDetailPage() {
|
||||
className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/10 px-5 py-3 text-sm font-bold text-white transition hover:border-white/20 hover:bg-white/15"
|
||||
>
|
||||
<BaseIcon path={mdiShareVariantOutline} size={16} />
|
||||
Compartir ruta
|
||||
Compartir
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -186,9 +186,9 @@ export default function RouteDetailPage() {
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-[1.5rem] border border-white/10 bg-[#04111f]/60 px-4 py-3 text-sm text-slate-200">
|
||||
<div className="font-semibold text-white">{progress}% completado</div>
|
||||
<div className="font-semibold text-white">Llevas {progress}%</div>
|
||||
<div className="mt-1 text-slate-400">
|
||||
{completedStops.length} de {route.stops.length} paradas hechas
|
||||
{completedStops.length} de {route.stops.length} ya hechas
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -229,21 +229,21 @@ export default function RouteDetailPage() {
|
||||
</div>
|
||||
<div className="flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-3 py-2 text-sm font-semibold text-slate-200">
|
||||
<BaseIcon path={mdiCheckCircleOutline} size={16} />
|
||||
{completed ? 'Completada' : 'Marcar parada'}
|
||||
{completed ? 'Ya está hecha' : 'Marcar parada'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-5 grid gap-3 md:grid-cols-3">
|
||||
<div className="rounded-[1.4rem] border border-white/10 bg-white/5 p-4">
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Especialidad</div>
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Prueba esto</div>
|
||||
<div className="mt-2 text-sm font-semibold text-white">{stop.specialty}</div>
|
||||
</div>
|
||||
<div className="rounded-[1.4rem] border border-white/10 bg-white/5 p-4">
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Horario aprox.</div>
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Mejor momento</div>
|
||||
<div className="mt-2 text-sm font-semibold text-white">{stop.hours}</div>
|
||||
</div>
|
||||
<div className="rounded-[1.4rem] border border-white/10 bg-white/5 p-4">
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Quédate</div>
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Quédate un rato</div>
|
||||
<div className="mt-2 text-sm font-semibold text-white">{stop.recommendedStay}</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -256,23 +256,23 @@ export default function RouteDetailPage() {
|
||||
<div className="space-y-6">
|
||||
<div className="rounded-[2rem] border border-white/10 bg-white/5 p-6 shadow-xl shadow-black/20">
|
||||
<div className="text-xs font-bold uppercase tracking-[0.35em] text-[#A7F3D0]">
|
||||
Tu ritmo ideal
|
||||
Hazla con calma
|
||||
</div>
|
||||
<div className="mt-3 flex items-center gap-3 text-white">
|
||||
<BaseIcon path={mdiClockOutline} size={18} />
|
||||
<div>
|
||||
<div className="text-xl font-black">{route.estimatedMinutes} minutos estimados</div>
|
||||
<div className="text-xl font-black">Más o menos {route.estimatedMinutes} min</div>
|
||||
<div className="text-sm text-slate-300">Planifica entre 3 y 5 horas para disfrutarla completa.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 rounded-[1.5rem] border border-white/10 bg-[#04111f]/60 p-4 text-sm leading-6 text-slate-300">
|
||||
{feedback || `Tu lista activa ahora mismo es “${activeList?.name || 'Mi chinchorreo'}”.`}
|
||||
{feedback || `Ahora mismo estás guardando en “${activeList?.name || 'Mi chinchorreo'}”.`}
|
||||
</div>
|
||||
<Link
|
||||
href="/mis-favoritos"
|
||||
className="mt-5 inline-flex items-center gap-2 text-sm font-semibold text-[#FDE68A]"
|
||||
>
|
||||
Abrir favoritos
|
||||
Ir a favoritos
|
||||
<BaseIcon path={mdiChevronRight} size={16} />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@ -86,8 +86,8 @@ export default function RoutesPage() {
|
||||
|
||||
setFeedback(
|
||||
result.added
|
||||
? `Ruta guardada en “${activeList?.name || 'Mi chinchorreo'}”.`
|
||||
: 'Esta ruta ya estaba guardada en tu lista activa.',
|
||||
? `Esa ruta se guardó en “${activeList?.name || 'Mi chinchorreo'}”.`
|
||||
: 'Esa ruta ya estaba en tu lista activa.',
|
||||
);
|
||||
};
|
||||
|
||||
@ -100,7 +100,7 @@ export default function RoutesPage() {
|
||||
<PublicShell
|
||||
activeSection="rutas"
|
||||
floatingAction={{
|
||||
label: 'Sorpréndeme con otra ruta',
|
||||
label: 'Dame otra ruta',
|
||||
icon: mdiDice5Outline,
|
||||
onClick: handleRandomRoute,
|
||||
}}
|
||||
@ -110,18 +110,17 @@ export default function RoutesPage() {
|
||||
<div className="max-w-3xl">
|
||||
<div className="text-xs font-bold uppercase tracking-[0.35em] text-[#FDE68A]">Rutas</div>
|
||||
<h1 className="mt-2 text-4xl font-black tracking-tight text-white">
|
||||
Explora la isla parada por parada
|
||||
Rutas para irte de parada en parada
|
||||
</h1>
|
||||
<p className="mt-3 text-base leading-7 text-slate-300">
|
||||
Aquí puedes descubrir rutas populares, ver sus paradas en orden,
|
||||
iniciar navegación y guardarlas en una lista personalizada.
|
||||
Descubre recorridos ya armados, mira cada parada en orden y guarda los que mejor van con tu plan.
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-[1.75rem] border border-white/10 bg-[#04111f]/60 p-4 text-sm text-slate-200">
|
||||
<div className="font-semibold text-white">Lista activa</div>
|
||||
<div className="font-semibold text-white">Tu lista activa</div>
|
||||
<div className="mt-1 text-[#FDE68A]">{activeList?.name || 'Mi chinchorreo'}</div>
|
||||
<Link href="/mis-favoritos" className="mt-3 inline-flex items-center gap-2 text-sm font-semibold text-[#A7F3D0]">
|
||||
Abrir favoritos
|
||||
Ir a favoritos
|
||||
<BaseIcon path={mdiChevronRight} size={16} />
|
||||
</Link>
|
||||
</div>
|
||||
@ -130,30 +129,30 @@ export default function RoutesPage() {
|
||||
<div className="mt-6 grid gap-4 rounded-[1.8rem] border border-white/10 bg-[#04111f]/50 p-4 md:grid-cols-[2fr_1fr_1fr] lg:grid-cols-[2fr_1fr_1fr_1fr]">
|
||||
<label className="block">
|
||||
<div className="mb-2 text-xs font-semibold uppercase tracking-[0.25em] text-slate-400">
|
||||
Buscar ruta
|
||||
Busca una ruta
|
||||
</div>
|
||||
<input
|
||||
value={searchValue}
|
||||
onChange={(event) => setSearchValue(event.target.value)}
|
||||
placeholder="Arecibo, montaña, mariscos, Guavate..."
|
||||
placeholder="Arecibo, Guavate, mariscos o montaña..."
|
||||
className="w-full rounded-2xl border border-white/10 bg-white/5 px-4 py-3 text-white placeholder:text-slate-400 focus:border-[#DAA520] focus:outline-none focus:ring-0"
|
||||
/>
|
||||
</label>
|
||||
|
||||
{[{
|
||||
title: 'Región',
|
||||
title: 'Zona',
|
||||
value: selectedRegion,
|
||||
options: regionFilters,
|
||||
onChange: setSelectedRegion,
|
||||
},
|
||||
{
|
||||
title: 'Dificultad',
|
||||
title: 'Ritmo',
|
||||
value: selectedDifficulty,
|
||||
options: difficultyFilters,
|
||||
onChange: setSelectedDifficulty,
|
||||
},
|
||||
{
|
||||
title: 'Etiqueta',
|
||||
title: 'Plan',
|
||||
value: selectedTag,
|
||||
options: tagFilters,
|
||||
onChange: setSelectedTag,
|
||||
@ -180,7 +179,7 @@ export default function RoutesPage() {
|
||||
<div className="mt-4 flex flex-wrap items-center gap-3 text-sm text-slate-300">
|
||||
<div className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-3 py-2">
|
||||
<BaseIcon path={mdiFilterVariant} size={16} />
|
||||
{filteredRoutes.length} rutas que van con tu plan
|
||||
{filteredRoutes.length} rutas para este plan
|
||||
</div>
|
||||
{feedback ? (
|
||||
<div className="inline-flex items-center gap-2 rounded-full border border-[#228B22]/30 bg-[#228B22]/10 px-3 py-2 text-[#A7F3D0]">
|
||||
@ -215,7 +214,7 @@ export default function RoutesPage() {
|
||||
<div className="font-semibold text-white">{route.bestFor}</div>
|
||||
<div className="mt-2 flex items-center gap-2 text-slate-300">
|
||||
<BaseIcon path={mdiClockOutline} size={16} />
|
||||
{route.estimatedMinutes} min estimados
|
||||
Aprox. {route.estimatedMinutes} min
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -233,15 +232,15 @@ export default function RoutesPage() {
|
||||
|
||||
<div className="mt-6 grid gap-3 md:grid-cols-3">
|
||||
<div className="rounded-[1.5rem] border border-white/10 bg-[#04111f]/60 p-4 text-sm text-slate-200">
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Paradas</div>
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Paradas clave</div>
|
||||
<div className="mt-2 text-2xl font-black text-white">{route.stops.length}</div>
|
||||
</div>
|
||||
<div className="rounded-[1.5rem] border border-white/10 bg-[#04111f]/60 p-4 text-sm text-slate-200">
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Dificultad</div>
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Ritmo</div>
|
||||
<div className="mt-2 text-xl font-black text-white">{route.difficulty}</div>
|
||||
</div>
|
||||
<div className="rounded-[1.5rem] border border-white/10 bg-[#04111f]/60 p-4 text-sm text-slate-200">
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Ideal para</div>
|
||||
<div className="text-xs uppercase tracking-[0.25em] text-slate-400">Buen plan para</div>
|
||||
<div className="mt-2 text-sm font-semibold text-white">{route.bestFor}</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -251,7 +250,7 @@ export default function RoutesPage() {
|
||||
href={`/rutas/${route.slug}`}
|
||||
className="inline-flex items-center gap-2 rounded-full bg-white px-5 py-3 text-sm font-bold text-[#04111f] transition hover:bg-slate-100"
|
||||
>
|
||||
Ver ruta
|
||||
Abrir ruta
|
||||
<BaseIcon path={mdiChevronRight} size={16} />
|
||||
</Link>
|
||||
<a
|
||||
@ -261,7 +260,7 @@ export default function RoutesPage() {
|
||||
className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-5 py-3 text-sm font-bold text-white transition hover:border-white/20 hover:bg-white/10"
|
||||
>
|
||||
<BaseIcon path={mdiCompassOutline} size={16} />
|
||||
Navegar
|
||||
Abrir en Maps
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
@ -274,7 +273,7 @@ export default function RoutesPage() {
|
||||
].join(' ')}
|
||||
>
|
||||
<BaseIcon path={mdiStarOutline} size={16} />
|
||||
{saved ? 'Ruta guardada' : 'Guardar ruta'}
|
||||
{saved ? 'Ya guardada' : 'Guardar'}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@ -283,7 +282,7 @@ export default function RoutesPage() {
|
||||
}
|
||||
className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-transparent px-5 py-3 text-sm font-bold text-slate-200 transition hover:border-white/20 hover:bg-white/5"
|
||||
>
|
||||
Compartir ruta
|
||||
Compartir
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -294,9 +293,9 @@ export default function RoutesPage() {
|
||||
|
||||
{!filteredRoutes.length ? (
|
||||
<section className="rounded-[2rem] border border-dashed border-white/15 bg-white/5 p-10 text-center shadow-xl shadow-black/20">
|
||||
<h2 className="text-2xl font-black text-white">Con esos filtros no salió ninguna ruta</h2>
|
||||
<h2 className="text-2xl font-black text-white">No encontramos ninguna ruta con esos filtros</h2>
|
||||
<p className="mt-3 text-sm leading-6 text-slate-300">
|
||||
Quita una etiqueta, cambia la dificultad o dale a “Sorpréndeme” para que aparezca otra opción.
|
||||
Prueba otra zona o ritmo, o dale a “Dame otra ruta” para ver una distinta.
|
||||
</p>
|
||||
<div className="mt-5 flex flex-wrap items-center justify-center gap-3">
|
||||
<button
|
||||
@ -309,14 +308,14 @@ export default function RoutesPage() {
|
||||
}}
|
||||
className="rounded-full bg-white px-5 py-3 text-sm font-bold text-[#04111f]"
|
||||
>
|
||||
Limpiar filtros
|
||||
Quitar filtros
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleRandomRoute}
|
||||
className="rounded-full border border-white/10 bg-white/5 px-5 py-3 text-sm font-bold text-white"
|
||||
>
|
||||
Sorpréndeme
|
||||
Dame otra ruta
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -28,20 +28,20 @@ export default function TipsPage() {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Chinchorreo PR | Tips & Guía del Viajero</title>
|
||||
<title>Chinchorreo PR | Tips</title>
|
||||
</Head>
|
||||
|
||||
<PublicShell activeSection="tips">
|
||||
<section className="grid gap-6 xl:grid-cols-[1.05fr_0.95fr]">
|
||||
<div className="rounded-[2rem] border border-white/10 bg-white/5 p-6 shadow-xl shadow-black/20 sm:p-8">
|
||||
<div className="text-xs font-bold uppercase tracking-[0.35em] text-[#FDE68A]">
|
||||
Tips & Guía del viajero
|
||||
Tips
|
||||
</div>
|
||||
<h1 className="mt-2 text-4xl font-black tracking-tight text-white">
|
||||
Consejos prácticos para chinchorrear con calma y responsabilidad
|
||||
Consejos para salir a chinchorrear con calma y buen juicio
|
||||
</h1>
|
||||
<p className="mt-3 max-w-2xl text-base leading-7 text-slate-300">
|
||||
Una guía educativa para salir mejor preparado, comer mejor y respetar cada lugar que visitas.
|
||||
Una guía sencilla para comer mejor, moverte con tiempo y cuidar cada parada que visites.
|
||||
</p>
|
||||
|
||||
<div className="mt-6 rounded-[1.9rem] border border-[#DAA520]/20 bg-gradient-to-br from-[#DAA520]/10 via-white/5 to-transparent p-6">
|
||||
@ -58,7 +58,7 @@ export default function TipsPage() {
|
||||
onClick={() => setTipIndex((current) => current + 1)}
|
||||
className="mt-5 inline-flex items-center gap-2 rounded-full bg-white px-5 py-3 text-sm font-bold text-[#04111f]"
|
||||
>
|
||||
Dame otro tip
|
||||
Quiero otro tip
|
||||
<BaseIcon path={mdiChevronRight} size={16} />
|
||||
</button>
|
||||
</div>
|
||||
@ -81,7 +81,7 @@ export default function TipsPage() {
|
||||
href="/rutas"
|
||||
className="mt-6 inline-flex items-center gap-2 text-sm font-semibold text-[#FDE68A]"
|
||||
>
|
||||
Ver rutas y poner estos tips en práctica
|
||||
Ir a rutas y ponerlos en práctica
|
||||
<BaseIcon path={mdiChevronRight} size={16} />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user