feat: replace geometric placeholders with real project and brand images
All checks were successful
Build & Push / build-and-push (push) Successful in 1m35s
All checks were successful
Build & Push / build-and-push (push) Successful in 1m35s
- Monaco Ocean: monaco_high_res.jpg in featured card - Port Nimara: anguilla.png in small card - Port Amador: panama.png in small card - Philosophy section: philosophy_image.png replaces AbstractGeometry - About "Our Story": our_story.png replaces StoryGeometry - Removed all geometric placeholder components (GeometricPlaceholder, AbstractGeometry, StoryGeometry) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
BIN
public/images/anguilla.png
Normal file
BIN
public/images/anguilla.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 MiB |
BIN
public/images/monaco_high_res.jpg
Normal file
BIN
public/images/monaco_high_res.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 636 KiB |
BIN
public/images/our_story.png
Normal file
BIN
public/images/our_story.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
BIN
public/images/panama.png
Normal file
BIN
public/images/panama.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
BIN
public/images/philosophy_image.png
Normal file
BIN
public/images/philosophy_image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
@@ -1,3 +1,4 @@
|
||||
import Image from 'next/image';
|
||||
import { setRequestLocale } from 'next-intl/server';
|
||||
import { Shield, PenTool, Users } from 'lucide-react';
|
||||
import ScrollReveal from '@/components/ui/ScrollReveal';
|
||||
@@ -39,125 +40,6 @@ const PILLARS = [
|
||||
|
||||
// ─── Sub-components ───────────────────────────────────────────────────────────
|
||||
|
||||
function StoryGeometry() {
|
||||
return (
|
||||
<div
|
||||
className="absolute inset-0 overflow-hidden rounded-xl"
|
||||
aria-hidden="true"
|
||||
>
|
||||
{/* Primary gradient circle — top right */}
|
||||
<div
|
||||
className="absolute rounded-full"
|
||||
style={{
|
||||
width: '70%',
|
||||
height: '70%',
|
||||
top: '-15%',
|
||||
right: '-15%',
|
||||
background:
|
||||
'radial-gradient(circle, rgba(91,164,217,0.10) 0%, rgba(0,100,148,0.05) 55%, transparent 100%)',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Secondary circle — bottom left */}
|
||||
<div
|
||||
className="absolute rounded-full"
|
||||
style={{
|
||||
width: '55%',
|
||||
height: '55%',
|
||||
bottom: '-10%',
|
||||
left: '-8%',
|
||||
background:
|
||||
'radial-gradient(circle, rgba(46,196,160,0.07) 0%, transparent 70%)',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Diagonal grid texture */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-[0.025]"
|
||||
style={{
|
||||
backgroundImage:
|
||||
'repeating-linear-gradient(-45deg, var(--color-primary-dark) 0, var(--color-primary-dark) 1px, transparent 0, transparent 50%)',
|
||||
backgroundSize: '28px 28px',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Tilted rectangle — left center */}
|
||||
<div
|
||||
className="absolute rounded-lg"
|
||||
style={{
|
||||
width: '24%',
|
||||
height: '34%',
|
||||
top: '18%',
|
||||
left: '6%',
|
||||
border: '1.5px solid rgba(91,164,217,0.12)',
|
||||
transform: 'rotate(-6deg)',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Dot field — right center */}
|
||||
<div
|
||||
className="absolute"
|
||||
style={{
|
||||
width: '28%',
|
||||
height: '28%',
|
||||
top: '30%',
|
||||
right: '8%',
|
||||
backgroundImage:
|
||||
'radial-gradient(circle, rgba(91,164,217,0.22) 1.5px, transparent 1.5px)',
|
||||
backgroundSize: '10px 10px',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Dashed arc */}
|
||||
<svg
|
||||
className="absolute"
|
||||
style={{ top: '15%', left: '28%', opacity: 0.07 }}
|
||||
width="160"
|
||||
height="160"
|
||||
viewBox="0 0 160 160"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle
|
||||
cx="80"
|
||||
cy="80"
|
||||
r="68"
|
||||
stroke="var(--color-primary-dark)"
|
||||
strokeWidth="1"
|
||||
strokeDasharray="7 5"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
{/* Small accent square */}
|
||||
<div
|
||||
className="absolute rounded-sm"
|
||||
style={{
|
||||
width: '5%',
|
||||
height: '5%',
|
||||
bottom: '26%',
|
||||
right: '26%',
|
||||
background: 'rgba(91,164,217,0.18)',
|
||||
transform: 'rotate(14deg)',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Teal accent line — bottom */}
|
||||
<div
|
||||
className="absolute"
|
||||
style={{
|
||||
width: '30%',
|
||||
height: '2px',
|
||||
bottom: '14%',
|
||||
left: '50%',
|
||||
transform: 'translateX(-50%)',
|
||||
background:
|
||||
'linear-gradient(to right, transparent, rgba(46,196,160,0.35), transparent)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function PillarCard({
|
||||
Icon,
|
||||
title,
|
||||
@@ -283,7 +165,13 @@ export default async function AboutPage({ params }: Props) {
|
||||
className="relative bg-surface rounded-xl overflow-hidden"
|
||||
style={{ minHeight: '460px' }}
|
||||
>
|
||||
<StoryGeometry />
|
||||
<Image
|
||||
src="/images/our_story.png"
|
||||
alt="Our story"
|
||||
fill
|
||||
className="object-cover rounded-xl"
|
||||
sizes="(max-width: 1024px) 100vw, 58vw"
|
||||
/>
|
||||
|
||||
{/* Inset rim */}
|
||||
<div
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import Image from 'next/image';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { cn } from '@/lib/utils';
|
||||
@@ -124,191 +125,6 @@ function PhilosophyPillar({
|
||||
);
|
||||
}
|
||||
|
||||
// ─── Abstract Geometric Decoration ───────────────────────────────────────────
|
||||
|
||||
function AbstractGeometry() {
|
||||
return (
|
||||
<div
|
||||
className="absolute inset-0 overflow-hidden rounded-xl"
|
||||
aria-hidden="true"
|
||||
>
|
||||
{/* Primary large circle — filled radial glow */}
|
||||
<div
|
||||
className="absolute rounded-full"
|
||||
style={{
|
||||
width: '65%',
|
||||
height: '65%',
|
||||
top: '-8%',
|
||||
right: '-12%',
|
||||
background:
|
||||
'radial-gradient(circle, rgba(91,164,217,0.12) 0%, rgba(0,100,148,0.06) 60%, transparent 100%)',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Large circle ring — border only, ~40% opacity */}
|
||||
<div
|
||||
className="absolute rounded-full"
|
||||
style={{
|
||||
width: '72%',
|
||||
height: '72%',
|
||||
top: '-18%',
|
||||
right: '-20%',
|
||||
border: '1px solid rgba(91,164,217,0.20)',
|
||||
opacity: 0.4,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Secondary circle, bottom-left */}
|
||||
<div
|
||||
className="absolute rounded-full"
|
||||
style={{
|
||||
width: '50%',
|
||||
height: '50%',
|
||||
bottom: '-10%',
|
||||
left: '-6%',
|
||||
background:
|
||||
'radial-gradient(circle, rgba(0,100,148,0.08) 0%, transparent 70%)',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Second smaller ring — bottom-left */}
|
||||
<div
|
||||
className="absolute rounded-full"
|
||||
style={{
|
||||
width: '38%',
|
||||
height: '38%',
|
||||
bottom: '-4%',
|
||||
left: '4%',
|
||||
border: '1px solid rgba(0,100,148,0.18)',
|
||||
opacity: 0.45,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Diagonal grid */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-[0.03]"
|
||||
style={{
|
||||
backgroundImage:
|
||||
'repeating-linear-gradient(-45deg, var(--color-primary-dark) 0, var(--color-primary-dark) 1px, transparent 0, transparent 50%)',
|
||||
backgroundSize: '32px 32px',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Diagonal line crossing the composition */}
|
||||
<div
|
||||
className="absolute"
|
||||
style={{
|
||||
width: '130%',
|
||||
height: '1px',
|
||||
top: '42%',
|
||||
left: '-15%',
|
||||
background:
|
||||
'linear-gradient(90deg, transparent 0%, rgba(91,164,217,0.18) 30%, rgba(0,100,148,0.22) 60%, transparent 100%)',
|
||||
transform: 'rotate(-12deg)',
|
||||
transformOrigin: 'left center',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Accent rectangle top-left, rotated */}
|
||||
<div
|
||||
className="absolute rounded-md"
|
||||
style={{
|
||||
width: '22%',
|
||||
height: '30%',
|
||||
top: '10%',
|
||||
left: '8%',
|
||||
border: '1.5px solid rgba(91,164,217,0.15)',
|
||||
transform: 'rotate(-8deg)',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Second rotated rectangle outline — center */}
|
||||
<div
|
||||
className="absolute rounded-sm"
|
||||
style={{
|
||||
width: '16%',
|
||||
height: '22%',
|
||||
top: '38%',
|
||||
left: '28%',
|
||||
border: '1px solid rgba(91,164,217,0.12)',
|
||||
transform: 'rotate(14deg)',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Floating dot cluster center-right */}
|
||||
<div
|
||||
className="absolute"
|
||||
style={{
|
||||
width: '22%',
|
||||
height: '22%',
|
||||
top: '35%',
|
||||
right: '10%',
|
||||
backgroundImage:
|
||||
'radial-gradient(circle, rgba(91,164,217,0.28) 1.5px, transparent 1.5px)',
|
||||
backgroundSize: '10px 10px',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Small dot cluster upper-left */}
|
||||
<div
|
||||
className="absolute"
|
||||
style={{
|
||||
width: '14%',
|
||||
height: '16%',
|
||||
top: '12%',
|
||||
right: '32%',
|
||||
backgroundImage:
|
||||
'radial-gradient(circle, rgba(0,100,148,0.20) 1.5px, transparent 1.5px)',
|
||||
backgroundSize: '8px 8px',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Thin dashed arc */}
|
||||
<svg
|
||||
className="absolute"
|
||||
style={{ top: '20%', left: '30%', opacity: 0.09 }}
|
||||
width="140"
|
||||
height="140"
|
||||
viewBox="0 0 140 140"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<circle
|
||||
cx="70"
|
||||
cy="70"
|
||||
r="60"
|
||||
stroke="var(--color-primary-dark)"
|
||||
strokeWidth="1"
|
||||
strokeDasharray="8 6"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
{/* Small solid accent square */}
|
||||
<div
|
||||
className="absolute rounded-sm"
|
||||
style={{
|
||||
width: '6%',
|
||||
height: '6%',
|
||||
bottom: '28%',
|
||||
right: '28%',
|
||||
background: 'rgba(91,164,217,0.22)',
|
||||
transform: 'rotate(12deg)',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Navy bottom overlay that fades upward — gives depth to pull-quote */}
|
||||
<div
|
||||
className="absolute inset-x-0 bottom-0 rounded-b-xl"
|
||||
style={{
|
||||
height: '45%',
|
||||
background:
|
||||
'linear-gradient(to top, rgba(28,43,58,0.55) 0%, rgba(28,43,58,0.18) 55%, transparent 100%)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ─── Main Component ───────────────────────────────────────────────────────────
|
||||
|
||||
export default function Philosophy() {
|
||||
@@ -374,7 +190,13 @@ export default function Philosophy() {
|
||||
'overflow-visible',
|
||||
)}
|
||||
>
|
||||
<AbstractGeometry />
|
||||
<Image
|
||||
src="/images/philosophy_image.png"
|
||||
alt="Craftsmanship and precision"
|
||||
fill
|
||||
className="object-cover rounded-xl"
|
||||
sizes="(max-width: 1024px) 100vw, 58vw"
|
||||
/>
|
||||
|
||||
{/* Subtle inner shadow rim */}
|
||||
<div
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
fadeVariants,
|
||||
viewportOnce,
|
||||
} from '@/lib/animations';
|
||||
import Image from 'next/image';
|
||||
import { Link } from '@/i18n/navigation';
|
||||
import { Lock, Clock, ArrowRight } from 'lucide-react';
|
||||
|
||||
@@ -21,6 +22,7 @@ interface Project {
|
||||
/** number of tags to resolve from the translation array */
|
||||
tagCount: number;
|
||||
featured?: boolean;
|
||||
image: string;
|
||||
}
|
||||
|
||||
interface ComingSoonItem {
|
||||
@@ -37,16 +39,19 @@ const PROJECTS: Project[] = [
|
||||
slug: 'monaco-ocean',
|
||||
tagCount: 2,
|
||||
featured: true,
|
||||
image: '/images/monaco_high_res.jpg',
|
||||
},
|
||||
{
|
||||
i18nKey: 'portNimara',
|
||||
slug: 'port-nimara',
|
||||
tagCount: 2,
|
||||
image: '/images/anguilla.png',
|
||||
},
|
||||
{
|
||||
i18nKey: 'portAmador',
|
||||
slug: 'port-amador',
|
||||
tagCount: 2,
|
||||
image: '/images/panama.png',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -86,274 +91,6 @@ const comingSoonVariants = {
|
||||
},
|
||||
};
|
||||
|
||||
// ─── Geometric Placeholder ────────────────────────────────────────────────────
|
||||
|
||||
function GeometricPlaceholder({
|
||||
variant = 'featured',
|
||||
cardVariant = 'default',
|
||||
className,
|
||||
}: {
|
||||
variant?: 'featured' | 'small';
|
||||
cardVariant?: 'default' | 'nimara' | 'amador';
|
||||
className?: string;
|
||||
}) {
|
||||
const isFeatured = variant === 'featured';
|
||||
|
||||
// Different gradient bases per card so secondary cards look distinct
|
||||
const gradientMap = {
|
||||
default: 'from-primary-dark/90 to-primary/70',
|
||||
nimara: 'from-navy/95 to-primary-dark/75',
|
||||
amador: 'from-[#1a3a4a]/95 to-primary/60',
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'relative overflow-hidden bg-gradient-to-br',
|
||||
gradientMap[cardVariant],
|
||||
className,
|
||||
)}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div className="absolute inset-0">
|
||||
|
||||
{isFeatured ? (
|
||||
/* ── Featured (Monaco): blueprint feel ── */
|
||||
<>
|
||||
{/* Large filled circle top-right */}
|
||||
<div
|
||||
className="absolute rounded-full bg-white/[0.06]"
|
||||
style={{ width: '55%', height: '55%', top: '-15%', right: '-10%' }}
|
||||
/>
|
||||
{/* Large circle ring — blueprint layer */}
|
||||
<div
|
||||
className="absolute rounded-full"
|
||||
style={{
|
||||
width: '45%',
|
||||
height: '45%',
|
||||
top: '10%',
|
||||
left: '5%',
|
||||
border: '1px solid rgba(255,255,255,0.12)',
|
||||
opacity: 0.4,
|
||||
}}
|
||||
/>
|
||||
{/* Medium circle bottom-left */}
|
||||
<div
|
||||
className="absolute rounded-full bg-white/[0.08]"
|
||||
style={{ width: '40%', height: '40%', bottom: '-20%', left: '-5%' }}
|
||||
/>
|
||||
{/* Subtle grid overlay (blueprint feel) */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-[0.035]"
|
||||
style={{
|
||||
backgroundImage:
|
||||
'linear-gradient(rgba(255,255,255,1) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,1) 1px, transparent 1px)',
|
||||
backgroundSize: '32px 32px',
|
||||
}}
|
||||
/>
|
||||
{/* Diagonal stripes very subtle */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-[0.025]"
|
||||
style={{
|
||||
backgroundImage:
|
||||
'repeating-linear-gradient(-45deg, #fff 0, #fff 1px, transparent 0, transparent 50%)',
|
||||
backgroundSize: '28px 28px',
|
||||
}}
|
||||
/>
|
||||
{/* Small dot cluster */}
|
||||
<div
|
||||
className="absolute opacity-[0.12]"
|
||||
style={{
|
||||
width: '20%',
|
||||
height: '20%',
|
||||
top: '55%',
|
||||
right: '18%',
|
||||
backgroundImage: 'radial-gradient(circle, #fff 1.5px, transparent 1.5px)',
|
||||
backgroundSize: '8px 8px',
|
||||
}}
|
||||
/>
|
||||
{/* Blueprint horizontal line — wide, white/20 */}
|
||||
<div
|
||||
className="absolute bg-white/[0.22] rounded-full"
|
||||
style={{ width: '60%', height: '1px', top: '50%', left: '5%' }}
|
||||
/>
|
||||
{/* Second thinner line below */}
|
||||
<div
|
||||
className="absolute bg-white/[0.10] rounded-full"
|
||||
style={{ width: '40%', height: '1px', top: 'calc(50% + 10px)', left: '5%' }}
|
||||
/>
|
||||
{/* Accent rotated rectangle */}
|
||||
<div
|
||||
className="absolute bg-white/[0.10] rounded-sm"
|
||||
style={{
|
||||
width: '18%',
|
||||
height: '28%',
|
||||
bottom: '18%',
|
||||
right: '15%',
|
||||
transform: 'rotate(-6deg)',
|
||||
}}
|
||||
/>
|
||||
{/* Small diagonal accent line */}
|
||||
<div
|
||||
className="absolute bg-white/[0.15]"
|
||||
style={{
|
||||
width: '25%',
|
||||
height: '1px',
|
||||
top: '28%',
|
||||
right: '8%',
|
||||
transform: 'rotate(-30deg)',
|
||||
transformOrigin: 'left center',
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
) : cardVariant === 'nimara' ? (
|
||||
/* ── Port Nimara: horizontal bands + arc ── */
|
||||
<>
|
||||
{/* Large arc ring top-left */}
|
||||
<div
|
||||
className="absolute rounded-full"
|
||||
style={{
|
||||
width: '80%',
|
||||
height: '80%',
|
||||
top: '-30%',
|
||||
left: '-20%',
|
||||
border: '1px solid rgba(255,255,255,0.10)',
|
||||
opacity: 0.5,
|
||||
}}
|
||||
/>
|
||||
{/* Smaller ring center */}
|
||||
<div
|
||||
className="absolute rounded-full"
|
||||
style={{
|
||||
width: '45%',
|
||||
height: '70%',
|
||||
bottom: '-15%',
|
||||
right: '-10%',
|
||||
border: '1px solid rgba(91,164,217,0.25)',
|
||||
}}
|
||||
/>
|
||||
{/* Horizontal rule band */}
|
||||
<div
|
||||
className="absolute bg-white/[0.06]"
|
||||
style={{ height: '28%', bottom: 0, left: 0, right: 0 }}
|
||||
/>
|
||||
{/* Fine horizontal lines */}
|
||||
<div
|
||||
className="absolute bg-white/20 rounded-full"
|
||||
style={{ width: '50%', height: '1px', top: '35%', right: '8%' }}
|
||||
/>
|
||||
<div
|
||||
className="absolute bg-white/10 rounded-full"
|
||||
style={{ width: '30%', height: '1px', top: '45%', right: '8%' }}
|
||||
/>
|
||||
{/* Dot cluster top-right */}
|
||||
<div
|
||||
className="absolute opacity-[0.14]"
|
||||
style={{
|
||||
width: '25%',
|
||||
height: '30%',
|
||||
top: '5%',
|
||||
right: '5%',
|
||||
backgroundImage: 'radial-gradient(circle, #fff 1.5px, transparent 1.5px)',
|
||||
backgroundSize: '8px 8px',
|
||||
}}
|
||||
/>
|
||||
{/* Diagonal line */}
|
||||
<div
|
||||
className="absolute bg-white/[0.12]"
|
||||
style={{
|
||||
width: '40%',
|
||||
height: '1px',
|
||||
top: '60%',
|
||||
left: '5%',
|
||||
transform: 'rotate(-20deg)',
|
||||
transformOrigin: 'left center',
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
/* ── Port Amador: triangular/radial composition ── */
|
||||
<>
|
||||
{/* Central radial glow */}
|
||||
<div
|
||||
className="absolute"
|
||||
style={{
|
||||
width: '70%',
|
||||
height: '70%',
|
||||
top: '-10%',
|
||||
right: '-15%',
|
||||
background:
|
||||
'radial-gradient(circle, rgba(91,164,217,0.18) 0%, transparent 70%)',
|
||||
}}
|
||||
/>
|
||||
{/* Diamond/rotated square accent */}
|
||||
<div
|
||||
className="absolute"
|
||||
style={{
|
||||
width: '30%',
|
||||
height: '50%',
|
||||
bottom: '-10%',
|
||||
left: '10%',
|
||||
border: '1px solid rgba(255,255,255,0.12)',
|
||||
transform: 'rotate(45deg)',
|
||||
}}
|
||||
/>
|
||||
{/* Diagonal stripes (different angle) */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-[0.03]"
|
||||
style={{
|
||||
backgroundImage:
|
||||
'repeating-linear-gradient(30deg, #fff 0, #fff 1px, transparent 0, transparent 50%)',
|
||||
backgroundSize: '20px 20px',
|
||||
}}
|
||||
/>
|
||||
{/* Top horizontal line */}
|
||||
<div
|
||||
className="absolute bg-white/20 rounded-full"
|
||||
style={{ width: '40%', height: '1px', top: '22%', left: '8%' }}
|
||||
/>
|
||||
{/* Small filled rectangle */}
|
||||
<div
|
||||
className="absolute bg-white/[0.12] rounded-sm"
|
||||
style={{
|
||||
width: '20%',
|
||||
height: '32%',
|
||||
top: '15%',
|
||||
right: '12%',
|
||||
transform: 'rotate(8deg)',
|
||||
}}
|
||||
/>
|
||||
{/* Dot accent bottom-right */}
|
||||
<div
|
||||
className="absolute opacity-[0.16]"
|
||||
style={{
|
||||
width: '22%',
|
||||
height: '22%',
|
||||
bottom: '8%',
|
||||
right: '8%',
|
||||
backgroundImage: 'radial-gradient(circle, #fff 1.5px, transparent 1.5px)',
|
||||
backgroundSize: '7px 7px',
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Bottom gradient fade — card bg color bleed for text readability */}
|
||||
<div
|
||||
className="absolute inset-x-0 bottom-0 h-2/5"
|
||||
style={{
|
||||
background: isFeatured
|
||||
? 'linear-gradient(to top, rgba(0,100,148,0.55) 0%, transparent 100%)'
|
||||
: cardVariant === 'nimara'
|
||||
? 'linear-gradient(to top, rgba(28,43,58,0.60) 0%, transparent 100%)'
|
||||
: 'linear-gradient(to top, rgba(26,58,74,0.55) 0%, transparent 100%)',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// ─── Tag Chip ─────────────────────────────────────────────────────────────────
|
||||
|
||||
function TagChip({ label, showDot = false }: { label: string; showDot?: boolean }) {
|
||||
@@ -383,12 +120,15 @@ function FeaturedCard({ project, readLabel, t }: { project: Project; readLabel:
|
||||
'transition-shadow duration-300 hover:shadow-[0_24px_48px_rgba(25,28,29,0.10)]',
|
||||
)}
|
||||
>
|
||||
{/* Geometric image placeholder */}
|
||||
<GeometricPlaceholder
|
||||
variant="featured"
|
||||
cardVariant="default"
|
||||
className="w-full aspect-[16/9] md:aspect-[2/1]"
|
||||
<div className="relative w-full aspect-[16/9] md:aspect-[2/1] overflow-hidden">
|
||||
<Image
|
||||
src={project.image}
|
||||
alt={t(`work.projects.${project.i18nKey}.title`)}
|
||||
fill
|
||||
className="object-cover transition-transform duration-500 group-hover:scale-[1.03]"
|
||||
sizes="(max-width: 768px) 100vw, 66vw"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex flex-col flex-1 p-7 gap-4">
|
||||
@@ -432,13 +172,7 @@ function FeaturedCard({ project, readLabel, t }: { project: Project; readLabel:
|
||||
|
||||
// ─── Small Card ───────────────────────────────────────────────────────────────
|
||||
|
||||
const SLUG_TO_VARIANT: Record<string, 'nimara' | 'amador'> = {
|
||||
'port-nimara': 'nimara',
|
||||
'port-amador': 'amador',
|
||||
};
|
||||
|
||||
function SmallCard({ project, readLabel, t }: { project: Project; readLabel: string; t: (key: string) => string }) {
|
||||
const cardVariant = SLUG_TO_VARIANT[project.slug] ?? 'nimara';
|
||||
const tags = Array.from({ length: project.tagCount }, (_, i) =>
|
||||
t(`work.projects.${project.i18nKey}.tags.${i}`),
|
||||
);
|
||||
@@ -453,7 +187,6 @@ function SmallCard({ project, readLabel, t }: { project: Project; readLabel: str
|
||||
'hover:shadow-subtle',
|
||||
)}
|
||||
>
|
||||
{/* Geometric placeholder — grayscale to color on hover */}
|
||||
<div className="relative overflow-hidden">
|
||||
<div
|
||||
className={cn(
|
||||
@@ -462,13 +195,17 @@ function SmallCard({ project, readLabel, t }: { project: Project; readLabel: str
|
||||
'opacity-80 group-hover:opacity-100',
|
||||
)}
|
||||
>
|
||||
<GeometricPlaceholder
|
||||
variant="small"
|
||||
cardVariant={cardVariant}
|
||||
className="w-full aspect-[16/7]"
|
||||
<div className="relative w-full aspect-[16/7]">
|
||||
<Image
|
||||
src={project.image}
|
||||
alt={t(`work.projects.${project.i18nKey}.title`)}
|
||||
fill
|
||||
className="object-cover"
|
||||
sizes="(max-width: 768px) 100vw, 33vw"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="flex flex-col flex-1 p-5 gap-3">
|
||||
|
||||
Reference in New Issue
Block a user