Apply La Huasca brand colors across layout, nav, login, admin, user and home
This commit is contained in:
+58
-20
@@ -10,6 +10,10 @@ interface ImageRecord {
|
|||||||
uploaded_at: string;
|
uploaded_at: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const gold = '#E8A849';
|
||||||
|
const navy = '#010D1E';
|
||||||
|
const warm = '#a6683c';
|
||||||
|
|
||||||
export default function AdminPage() {
|
export default function AdminPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [images, setImages] = useState<ImageRecord[]>([]);
|
const [images, setImages] = useState<ImageRecord[]>([]);
|
||||||
@@ -73,25 +77,47 @@ export default function AdminPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (loading) return <main style={{ padding: '2rem' }}><p>Loading...</p></main>;
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<main style={{ padding: '2rem', color: warm, fontSize: '18px' }}>
|
||||||
|
<p>Loading gallery...</p>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main style={{ padding: '2rem' }}>
|
<main style={{ padding: '2rem', maxWidth: '72rem', margin: '0 auto' }}>
|
||||||
<h1>Admin Portal</h1>
|
<h1 style={{ fontSize: 'clamp(28px, 4vw, 42px)', fontWeight: 400, fontStyle: 'italic', color: navy, margin: '0 0 0.5rem' }}>
|
||||||
<p>Total uploaded images: <strong>{count}</strong></p>
|
Admin Portal
|
||||||
{error && <p style={{ color: 'crimson' }}>{error}</p>}
|
</h1>
|
||||||
|
<p style={{ color: '#555', marginBottom: '1.5rem' }}>
|
||||||
|
Total uploaded images: <strong style={{ color: warm }}>{count}</strong>
|
||||||
|
</p>
|
||||||
|
{error && <p style={{ color: '#c23b22', marginBottom: '1rem' }}>{error}</p>}
|
||||||
<label
|
<label
|
||||||
style={{
|
style={{
|
||||||
display: 'inline-block',
|
display: 'inline-flex',
|
||||||
padding: '0.75rem 1rem',
|
alignItems: 'center',
|
||||||
background: '#1a1a1a',
|
gap: '0.5rem',
|
||||||
color: '#fff',
|
padding: '0.75rem 1.25rem',
|
||||||
borderRadius: '4px',
|
background: gold,
|
||||||
|
color: navy,
|
||||||
|
borderRadius: '999px',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
marginBottom: '1rem',
|
fontWeight: 600,
|
||||||
|
marginBottom: '1.5rem',
|
||||||
|
transition: 'transform .12s, box-shadow .15s',
|
||||||
|
}}
|
||||||
|
onMouseEnter={(e) => {
|
||||||
|
e.currentTarget.style.transform = 'translateY(-1px)';
|
||||||
|
e.currentTarget.style.boxShadow = '0 6px 18px rgba(232,168,73,0.35)';
|
||||||
|
}}
|
||||||
|
onMouseLeave={(e) => {
|
||||||
|
e.currentTarget.style.transform = 'translateY(0)';
|
||||||
|
e.currentTarget.style.boxShadow = 'none';
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Upload images
|
+ Upload images
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
@@ -101,39 +127,51 @@ export default function AdminPage() {
|
|||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
{images.length === 0 ? (
|
{images.length === 0 ? (
|
||||||
<p style={{ color: 'dimgray' }}>No images uploaded yet.</p>
|
<p style={{ color: '#777' }}>No images uploaded yet.</p>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'grid',
|
display: 'grid',
|
||||||
gridTemplateColumns: 'repeat(auto-fill, minmax(180px, 1fr))',
|
gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))',
|
||||||
gap: '1rem',
|
gap: '1.25rem',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{images.map((img) => (
|
{images.map((img) => (
|
||||||
<div
|
<div
|
||||||
key={img.id}
|
key={img.id}
|
||||||
style={{
|
style={{
|
||||||
border: '1px solid #ddd',
|
borderRadius: '16px',
|
||||||
borderRadius: '8px',
|
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
background: '#f5f0e8',
|
||||||
|
boxShadow: '0 1px 2px rgba(1,13,30,0.08)',
|
||||||
|
transition: 'transform .2s, box-shadow .2s',
|
||||||
|
}}
|
||||||
|
onMouseEnter={(e) => {
|
||||||
|
e.currentTarget.style.transform = 'translateY(-2px)';
|
||||||
|
e.currentTarget.style.boxShadow = '0 6px 18px rgba(14,47,71,0.16)';
|
||||||
|
}}
|
||||||
|
onMouseLeave={(e) => {
|
||||||
|
e.currentTarget.style.transform = 'translateY(0)';
|
||||||
|
e.currentTarget.style.boxShadow = '0 1px 2px rgba(1,13,30,0.08)';
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={img.data}
|
src={img.data}
|
||||||
alt={img.filename}
|
alt={img.filename}
|
||||||
style={{ width: '100%', height: '160px', objectFit: 'cover' }}
|
style={{ width: '100%', height: '180px', objectFit: 'cover' }}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleDelete(img.id)}
|
onClick={() => handleDelete(img.id)}
|
||||||
style={{
|
style={{
|
||||||
padding: '0.5rem',
|
padding: '0.65rem',
|
||||||
background: 'crimson',
|
background: '#c23b22',
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
|
fontSize: '14px',
|
||||||
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Delete
|
Delete
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ export default function RootLayout({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body style={{ margin: 0, fontFamily: 'system-ui, sans-serif' }}>
|
<body style={{ margin: 0, fontFamily: 'system-ui, sans-serif', background: '#FAF7F0', color: '#1a1a1a' }}>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
{children}
|
{children}
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+73
-18
@@ -30,58 +30,113 @@ export default function LoginPage() {
|
|||||||
router.push(data.role === 'admin' ? '/admin' : '/user');
|
router.push(data.role === 'admin' ? '/admin' : '/user');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const accent = '#E8A849';
|
||||||
|
const navy = '#010D1E';
|
||||||
|
const cream = '#f5f0e8';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main style={{ padding: '2rem', maxWidth: '28rem', margin: '0 auto' }}>
|
<main
|
||||||
<h1 style={{ marginBottom: '1rem' }}>Login</h1>
|
style={{
|
||||||
|
minHeight: 'calc(100vh - 56px)',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
padding: '2rem',
|
||||||
|
background: '#FAF7F0',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
style={{
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: '26rem',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
gap: '1rem',
|
gap: '1.25rem',
|
||||||
padding: '1.5rem',
|
padding: '2.5rem',
|
||||||
border: '1px solid #ddd',
|
background: cream,
|
||||||
borderRadius: '8px',
|
borderRadius: '16px',
|
||||||
|
boxShadow: '0 6px 18px rgba(14,47,71,0.12)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<label style={{ display: 'flex', flexDirection: 'column', gap: '0.25rem' }}>
|
<h1
|
||||||
|
style={{
|
||||||
|
margin: '0 0 0.25rem',
|
||||||
|
fontSize: 'clamp(28px, 4vw, 40px)',
|
||||||
|
fontWeight: 400,
|
||||||
|
fontStyle: 'italic',
|
||||||
|
color: navy,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Welcome back
|
||||||
|
</h1>
|
||||||
|
<p style={{ margin: '0 0 1rem', color: '#555' }}>Log in to your portal.</p>
|
||||||
|
|
||||||
|
<label style={{ display: 'flex', flexDirection: 'column', gap: '0.35rem', fontSize: '12px', letterSpacing: '0.06em', textTransform: 'uppercase', color: '#555' }}>
|
||||||
Username
|
Username
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={username}
|
value={username}
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
style={{ padding: '0.5rem', borderRadius: '4px', border: '1px solid #ccc' }}
|
style={{
|
||||||
|
padding: '0.75rem 0.9rem',
|
||||||
|
borderRadius: '12px',
|
||||||
|
border: '1px solid rgba(1,13,30,0.18)',
|
||||||
|
background: '#fff',
|
||||||
|
fontSize: '15px',
|
||||||
|
color: navy,
|
||||||
|
outline: 'none',
|
||||||
|
}}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label style={{ display: 'flex', flexDirection: 'column', gap: '0.25rem' }}>
|
<label style={{ display: 'flex', flexDirection: 'column', gap: '0.35rem', fontSize: '12px', letterSpacing: '0.06em', textTransform: 'uppercase', color: '#555' }}>
|
||||||
Password
|
Password
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
value={password}
|
value={password}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
style={{ padding: '0.5rem', borderRadius: '4px', border: '1px solid #ccc' }}
|
style={{
|
||||||
|
padding: '0.75rem 0.9rem',
|
||||||
|
borderRadius: '12px',
|
||||||
|
border: '1px solid rgba(1,13,30,0.18)',
|
||||||
|
background: '#fff',
|
||||||
|
fontSize: '15px',
|
||||||
|
color: navy,
|
||||||
|
outline: 'none',
|
||||||
|
}}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
{error && <p style={{ color: 'crimson', margin: 0 }}>{error}</p>}
|
{error && <p style={{ color: '#c23b22', margin: 0, fontSize: '14px' }}>{error}</p>}
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
style={{
|
style={{
|
||||||
padding: '0.75rem',
|
padding: '0.85rem',
|
||||||
background: '#1a1a1a',
|
background: accent,
|
||||||
color: '#fff',
|
color: navy,
|
||||||
border: 'none',
|
border: 'none',
|
||||||
borderRadius: '4px',
|
borderRadius: '999px',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
|
fontSize: '15px',
|
||||||
|
fontWeight: 600,
|
||||||
|
transition: 'transform .12s, box-shadow .15s',
|
||||||
|
}}
|
||||||
|
onMouseEnter={(e) => {
|
||||||
|
e.currentTarget.style.transform = 'translateY(-1px)';
|
||||||
|
e.currentTarget.style.boxShadow = '0 6px 18px rgba(232,168,73,0.35)';
|
||||||
|
}}
|
||||||
|
onMouseLeave={(e) => {
|
||||||
|
e.currentTarget.style.transform = 'translateY(0)';
|
||||||
|
e.currentTarget.style.boxShadow = 'none';
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Log in
|
Log in
|
||||||
</button>
|
</button>
|
||||||
</form>
|
<p style={{ margin: '0.5rem 0 0', fontSize: '13px', color: '#777', textAlign: 'center' }}>
|
||||||
<p style={{ marginTop: '1rem', color: 'dimgray' }}>
|
Demo accounts: <strong style={{ color: navy }}>admin</strong> / admin and <strong style={{ color: navy }}>user</strong> / user.
|
||||||
Demo accounts: <strong>admin</strong> / admin and <strong>user</strong> / user.
|
|
||||||
</p>
|
</p>
|
||||||
|
</form>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-3
@@ -1,10 +1,50 @@
|
|||||||
import MeasuredText from '@/components/MeasuredText';
|
import MeasuredText from '@/components/MeasuredText';
|
||||||
|
|
||||||
|
const gold = '#E8A849';
|
||||||
|
const navy = '#010D1E';
|
||||||
|
const cream = '#f5f0e8';
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
return (
|
return (
|
||||||
<main style={{ padding: '2rem' }}>
|
<main
|
||||||
<h1>La Huasca</h1>
|
style={{
|
||||||
<p>Welcome to the TypeScript + Next.js version of La Huasca.</p>
|
padding: 'clamp(3rem, 9vw, 7rem) 2rem',
|
||||||
|
minHeight: 'calc(100vh - 56px)',
|
||||||
|
background: navy,
|
||||||
|
color: cream,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
textAlign: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
style={{
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
fontSize: '12px',
|
||||||
|
letterSpacing: '0.18em',
|
||||||
|
textTransform: 'uppercase',
|
||||||
|
color: gold,
|
||||||
|
margin: '0 0 1rem',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Hotel · Restaurant · Vineyard
|
||||||
|
</p>
|
||||||
|
<h1
|
||||||
|
style={{
|
||||||
|
fontSize: 'clamp(44px, 7vw, 84px)',
|
||||||
|
fontWeight: 400,
|
||||||
|
fontStyle: 'italic',
|
||||||
|
lineHeight: 1.08,
|
||||||
|
margin: '0 0 1.25rem',
|
||||||
|
color: cream,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
La Huasca
|
||||||
|
</h1>
|
||||||
|
<p style={{ fontSize: '18px', lineHeight: 1.55, color: 'rgba(245,240,232,0.78)', maxWidth: '52ch', margin: '0 0 2rem' }}>
|
||||||
|
Welcome to the TypeScript + Next.js version of La Huasca.
|
||||||
|
</p>
|
||||||
<MeasuredText text="Hello, Pretext!" />
|
<MeasuredText text="Hello, Pretext!" />
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
|||||||
+97
-42
@@ -31,6 +31,11 @@ interface PortalData {
|
|||||||
wifiPassword: string;
|
wifiPassword: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const gold = '#E8A849';
|
||||||
|
const navy = '#010D1E';
|
||||||
|
const cream = '#f5f0e8';
|
||||||
|
const warm = '#a6683c';
|
||||||
|
|
||||||
export default function UserPage() {
|
export default function UserPage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [data, setData] = useState<PortalData | null>(null);
|
const [data, setData] = useState<PortalData | null>(null);
|
||||||
@@ -53,94 +58,144 @@ export default function UserPage() {
|
|||||||
.finally(() => setLoading(false));
|
.finally(() => setLoading(false));
|
||||||
}, [router]);
|
}, [router]);
|
||||||
|
|
||||||
if (loading) return <main style={{ padding: '2rem' }}><p>Loading...</p></main>;
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<main style={{ padding: '2rem', color: warm, fontSize: '18px' }}>
|
||||||
|
<p>Loading your portal...</p>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return <main style={{ padding: '2rem' }}><p>Please log in as user to access this page.</p></main>;
|
return <main style={{ padding: '2rem' }}><p>Please log in as user to access this page.</p></main>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main style={{ padding: '2rem', maxWidth: '48rem', margin: '0 auto' }}>
|
<main style={{ padding: '2rem', maxWidth: '56rem', margin: '0 auto' }}>
|
||||||
<h1>User Portal</h1>
|
<h1 style={{ fontSize: 'clamp(28px, 4vw, 42px)', fontWeight: 400, fontStyle: 'italic', color: navy, margin: '0 0 2rem' }}>
|
||||||
|
Member Portal
|
||||||
|
</h1>
|
||||||
|
|
||||||
<section style={{ marginBottom: '2rem' }}>
|
<Section title="Future Reservations">
|
||||||
<h2>Future Reservations</h2>
|
|
||||||
{data.reservations.length === 0 ? (
|
{data.reservations.length === 0 ? (
|
||||||
<p style={{ color: 'dimgray' }}>No upcoming reservations.</p>
|
<p style={{ color: '#777' }}>No upcoming reservations.</p>
|
||||||
) : (
|
) : (
|
||||||
<ul style={{ padding: 0, listStyle: 'none' }}>
|
<ul style={{ padding: 0, listStyle: 'none', display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
|
||||||
{data.reservations.map((r) => (
|
{data.reservations.map((r) => (
|
||||||
<li
|
<li
|
||||||
key={r.id}
|
key={r.id}
|
||||||
style={{
|
style={{
|
||||||
padding: '1rem',
|
padding: '1rem 1.25rem',
|
||||||
marginBottom: '0.5rem',
|
background: cream,
|
||||||
border: '1px solid #ddd',
|
borderRadius: '16px',
|
||||||
borderRadius: '8px',
|
boxShadow: '0 1px 2px rgba(1,13,30,0.08)',
|
||||||
|
color: navy,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{r.date} at {r.time} · {r.guests} guests · {r.table_name}
|
<strong style={{ color: warm }}>{r.date}</strong> at {r.time} · {r.guests} guests · {r.table_name}
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
)}
|
)}
|
||||||
</section>
|
</Section>
|
||||||
|
|
||||||
<section style={{ marginBottom: '2rem' }}>
|
<Section title="Discount Coupons">
|
||||||
<h2>Discount Coupons</h2>
|
|
||||||
<div style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap' }}>
|
<div style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap' }}>
|
||||||
{data.coupons.map((c) => (
|
{data.coupons.map((c) => (
|
||||||
<div
|
<div
|
||||||
key={c.id}
|
key={c.id}
|
||||||
style={{
|
style={{
|
||||||
padding: '1rem',
|
padding: '1.25rem',
|
||||||
border: '2px dashed #1a1a1a',
|
background: cream,
|
||||||
borderRadius: '8px',
|
border: '2px dashed ' + warm,
|
||||||
minWidth: '12rem',
|
borderRadius: '16px',
|
||||||
|
minWidth: '13rem',
|
||||||
|
color: navy,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<strong>{c.code}</strong>
|
<strong style={{ fontSize: '18px', color: warm }}>{c.code}</strong>
|
||||||
<p style={{ margin: '0.5rem 0 0', color: 'dimgray' }}>{c.discount}</p>
|
<p style={{ margin: '0.5rem 0 0', color: '#555', fontSize: '14px' }}>{c.discount}</p>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</Section>
|
||||||
|
|
||||||
<section style={{ marginBottom: '2rem' }}>
|
<Section title="Offers">
|
||||||
<h2>Offers</h2>
|
<ul style={{ padding: 0, listStyle: 'none', display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
|
||||||
<ul>
|
|
||||||
{data.offers.map((o) => (
|
{data.offers.map((o) => (
|
||||||
<li key={o.id}>
|
<li
|
||||||
<strong>{o.title}</strong> — {o.description}
|
key={o.id}
|
||||||
|
style={{
|
||||||
|
padding: '1rem 1.25rem',
|
||||||
|
background: cream,
|
||||||
|
borderRadius: '16px',
|
||||||
|
color: navy,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<strong style={{ color: warm }}>{o.title}</strong> — {o.description}
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</Section>
|
||||||
|
|
||||||
<section style={{ marginBottom: '2rem' }}>
|
<Section title="WiFi Password">
|
||||||
<h2>WiFi Password</h2>
|
<div
|
||||||
<p
|
|
||||||
style={{
|
style={{
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
padding: '0.75rem 1.5rem',
|
padding: '0.9rem 2rem',
|
||||||
background: '#f4f4f4',
|
background: navy,
|
||||||
borderRadius: '8px',
|
color: cream,
|
||||||
|
borderRadius: '12px',
|
||||||
fontFamily: 'monospace',
|
fontFamily: 'monospace',
|
||||||
fontSize: '1.25rem',
|
fontSize: '1.4rem',
|
||||||
|
letterSpacing: '0.04em',
|
||||||
|
boxShadow: '0 4px 12px rgba(1,13,30,0.2)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{data.wifiPassword}
|
{data.wifiPassword}
|
||||||
</p>
|
</div>
|
||||||
</section>
|
</Section>
|
||||||
|
|
||||||
<section>
|
<Section title="Member Benefits">
|
||||||
<h2>Member Benefits</h2>
|
<ul style={{ padding: 0, listStyle: 'none', display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(260px, 1fr))', gap: '0.75rem' }}>
|
||||||
<ul>
|
|
||||||
{data.benefits.map((b) => (
|
{data.benefits.map((b) => (
|
||||||
<li key={b}>{b}</li>
|
<li
|
||||||
|
key={b}
|
||||||
|
style={{
|
||||||
|
padding: '0.9rem 1.1rem',
|
||||||
|
background: '#e8eff3',
|
||||||
|
borderLeft: '4px solid ' + gold,
|
||||||
|
borderRadius: '0 12px 12px 0',
|
||||||
|
color: navy,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{b}
|
||||||
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</Section>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Section({ title, children }: { title: string; children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<section style={{ marginBottom: '2.5rem' }}>
|
||||||
|
<h2
|
||||||
|
style={{
|
||||||
|
fontSize: '20px',
|
||||||
|
fontWeight: 600,
|
||||||
|
letterSpacing: '-0.01em',
|
||||||
|
color: navy,
|
||||||
|
margin: '0 0 1rem',
|
||||||
|
paddingBottom: '0.4rem',
|
||||||
|
borderBottom: '1.5px solid ' + warm,
|
||||||
|
display: 'inline-block',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
|
{children}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ export default function MeasuredText({ text }: MeasuredTextProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<span ref={ref} style={{ fontSize: '2rem', fontWeight: 700 }}>
|
<span ref={ref} style={{ fontSize: '2rem', fontWeight: 700, color: '#E8A849' }}>
|
||||||
{text}
|
{text}
|
||||||
</span>
|
</span>
|
||||||
{height !== null && (
|
{height !== null && (
|
||||||
<p style={{ color: 'dimgray' }}>Measured height: {height.toFixed(2)}px</p>
|
<p style={{ color: 'rgba(245,240,232,0.6)' }}>Measured height: {height.toFixed(2)}px</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
+43
-19
@@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import { usePathname } from 'next/navigation';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ const links = [
|
|||||||
export default function Navbar() {
|
export default function Navbar() {
|
||||||
const [auth, setAuth] = useState<{ authenticated: boolean; role?: string } | null>(null);
|
const [auth, setAuth] = useState<{ authenticated: boolean; role?: string } | null>(null);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const pathname = usePathname();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch('/api/auth/me', { credentials: 'same-origin' })
|
fetch('/api/auth/me', { credentials: 'same-origin' })
|
||||||
@@ -29,28 +31,46 @@ export default function Navbar() {
|
|||||||
router.push('/login');
|
router.push('/login');
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
const navStyle: React.CSSProperties = {
|
||||||
<nav
|
|
||||||
style={{
|
|
||||||
position: 'sticky',
|
position: 'sticky',
|
||||||
top: 0,
|
top: 0,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
gap: '1.5rem',
|
gap: '1.5rem',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: '1rem 2rem',
|
padding: '0.75rem 1.5rem',
|
||||||
background: '#1a1a1a',
|
background: '#010D1E',
|
||||||
color: '#fff',
|
color: '#f5f0e8',
|
||||||
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
|
boxShadow: '0 2px 8px rgba(1,13,30,0.25)',
|
||||||
}}
|
zIndex: 50,
|
||||||
>
|
};
|
||||||
<Link href="/" style={{ fontWeight: 700, color: '#fff', textDecoration: 'none' }}>
|
|
||||||
|
const linkBase: React.CSSProperties = {
|
||||||
|
color: 'rgba(245,240,232,0.85)',
|
||||||
|
textDecoration: 'none',
|
||||||
|
fontSize: '14px',
|
||||||
|
padding: '6px 0',
|
||||||
|
borderBottom: '1.5px solid transparent',
|
||||||
|
transition: 'color .15s, border-color .15s',
|
||||||
|
};
|
||||||
|
|
||||||
|
const activeLink: React.CSSProperties = {
|
||||||
|
color: '#E8A849',
|
||||||
|
borderBottomColor: '#E8A849',
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav style={navStyle}>
|
||||||
|
<Link href="/" style={{ fontWeight: 700, color: '#E8A849', textDecoration: 'none', fontSize: '20px', fontStyle: 'italic' }}>
|
||||||
La Huasca
|
La Huasca
|
||||||
</Link>
|
</Link>
|
||||||
{links.map((link) => (
|
{links.map((link) => (
|
||||||
<Link
|
<Link
|
||||||
key={link.href}
|
key={link.href}
|
||||||
href={link.href}
|
href={link.href}
|
||||||
style={{ color: '#e5e5e5', textDecoration: 'none' }}
|
style={{
|
||||||
|
...linkBase,
|
||||||
|
...(pathname === link.href ? activeLink : {}),
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{link.label}
|
{link.label}
|
||||||
</Link>
|
</Link>
|
||||||
@@ -61,11 +81,13 @@ export default function Navbar() {
|
|||||||
style={{
|
style={{
|
||||||
marginLeft: 'auto',
|
marginLeft: 'auto',
|
||||||
background: 'transparent',
|
background: 'transparent',
|
||||||
border: '1px solid #fff',
|
border: '1px solid #E8A849',
|
||||||
color: '#fff',
|
color: '#E8A849',
|
||||||
padding: '0.4rem 0.75rem',
|
padding: '0.4rem 0.9rem',
|
||||||
borderRadius: '4px',
|
borderRadius: '999px',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
|
fontSize: '13px',
|
||||||
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Logout
|
Logout
|
||||||
@@ -75,11 +97,13 @@ export default function Navbar() {
|
|||||||
href="/login"
|
href="/login"
|
||||||
style={{
|
style={{
|
||||||
marginLeft: 'auto',
|
marginLeft: 'auto',
|
||||||
color: '#e5e5e5',
|
color: '#010D1E',
|
||||||
textDecoration: 'none',
|
textDecoration: 'none',
|
||||||
border: '1px solid #e5e5e5',
|
background: '#E8A849',
|
||||||
padding: '0.4rem 0.75rem',
|
padding: '0.45rem 0.9rem',
|
||||||
borderRadius: '4px',
|
borderRadius: '999px',
|
||||||
|
fontSize: '13px',
|
||||||
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Login
|
Login
|
||||||
|
|||||||
Reference in New Issue
Block a user