Admin portal, public pages, footer, site config

This commit is contained in:
2026-06-27 18:10:49 -05:00
parent 4bb3596412
commit 75da132327
9 changed files with 1011 additions and 227 deletions
+87 -3
View File
@@ -1,8 +1,92 @@
'use client';
import { useEffect, useState } from 'react';
interface Place {
id: number;
name: string;
description: string;
photo: string | null;
distance_km: string | null;
visit_time: string | null;
suggestion: string | null;
}
const gold = '#E8A849';
const navy = '#010D1E';
const cream = '#f5f0e8';
const warm = '#a6683c';
export default function LandscapePage() {
const [places, setPlaces] = useState<Place[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
useEffect(() => {
fetch('/api/places')
.then(async (res) => {
if (!res.ok) throw new Error('Failed to load places');
const json = await res.json();
setPlaces(json.data || []);
})
.catch((err) => setError(err.message))
.finally(() => setLoading(false));
}, []);
return (
<main style={{ padding: '2rem' }}>
<h1>Landscape</h1>
<p>Explore the trails, rivers, and cloud forest around La Huasca.</p>
<main style={{ padding: '2rem', maxWidth: '72rem', margin: '0 auto', minHeight: '60vh' }}>
<h1 style={{ fontSize: 'clamp(32px, 5vw, 48px)', fontWeight: 400, fontStyle: 'italic', color: navy, margin: '0 0 0.5rem' }}>Landscape</h1>
<p style={{ color: '#555', marginBottom: '2rem', maxWidth: '50ch' }}>
Trails, rivers, waterfalls, and villages around La Huasca.
</p>
{loading && <p style={{ color: warm }}>Loading places...</p>}
{error && <p style={{ color: '#c23b22' }}>{error}</p>}
{!loading && places.length === 0 && <p style={{ color: '#777' }}>No places added yet.</p>}
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))', gap: '1.5rem' }}>
{places.map((place) => (
<article
key={place.id}
style={{
background: cream,
borderRadius: '20px',
overflow: 'hidden',
boxShadow: '0 2px 8px rgba(1,13,30,0.08)',
display: 'flex',
flexDirection: 'column',
transition: 'transform 0.2s, box-shadow 0.2s',
}}
onMouseEnter={(e) => { e.currentTarget.style.transform = 'translateY(-3px)'; e.currentTarget.style.boxShadow = '0 8px 24px rgba(1,13,30,0.14)'; }}
onMouseLeave={(e) => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = '0 2px 8px rgba(1,13,30,0.08)'; }}
>
<div
style={{
height: '200px',
background: '#ddd',
backgroundImage: place.photo ? `url(${place.photo})` : undefined,
backgroundSize: 'cover',
backgroundPosition: 'center',
}}
/>
<div style={{ padding: '1.5rem', flex: 1 }}>
<h2 style={{ margin: '0 0 0.5rem', color: navy }}>{place.name}</h2>
<p style={{ color: '#555', lineHeight: 1.5 }}>{place.description}</p>
<div style={{ marginTop: '1rem', display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>
{place.distance_km && <span style={{ fontSize: '13px', background: '#e8eff3', color: navy, padding: '0.3rem 0.7rem', borderRadius: '999px' }}>{place.distance_km} km</span>}
{place.visit_time && <span style={{ fontSize: '13px', background: '#e8eff3', color: navy, padding: '0.3rem 0.7rem', borderRadius: '999px' }}>{place.visit_time}</span>}
</div>
{place.suggestion && (
<div style={{ marginTop: '1rem', padding: '0.75rem', background: '#fff', borderLeft: '3px solid ' + gold, borderRadius: '0 10px 10px 0' }}>
<strong style={{ fontSize: '13px', color: warm }}>Suggestion:</strong>
<p style={{ margin: '0.25rem 0 0', fontSize: '14px', color: '#555' }}>{place.suggestion}</p>
</div>
)}
</div>
</article>
))}
</div>
</main>
);
}