99 lines
3.5 KiB
TypeScript
99 lines
3.5 KiB
TypeScript
import React from 'react'
|
|
|
|
type Skill = {
|
|
icon: string
|
|
title: string
|
|
tags: string
|
|
}
|
|
|
|
type BentoRowBlockProps = {
|
|
aboutHeading?: string
|
|
aboutText?: string
|
|
aboutCta?: { label?: string; url?: string; newTab?: boolean }
|
|
skillsHeading?: string
|
|
skills?: Skill[]
|
|
}
|
|
|
|
export function BentoRowBlock(props: BentoRowBlockProps) {
|
|
const { aboutHeading, aboutText, aboutCta, skillsHeading, skills } = props
|
|
|
|
return (
|
|
// Standardized vertical padding and container constraints
|
|
<section className="w-full max-w-5xl mx-auto py-20 md:py-28">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
{/* About Section */}
|
|
<div className="bg-muted/50 border border-foreground/10 rounded-2xl p-8 flex flex-col justify-between gap-8">
|
|
<div>
|
|
{aboutHeading && (
|
|
<p className="text-[10px] font-bold tracking-[0.2em] uppercase text-foreground/30 mb-6">
|
|
{aboutHeading}
|
|
</p>
|
|
)}
|
|
{aboutText && (
|
|
<p className="text-sm text-foreground/60 leading-relaxed whitespace-pre-line">
|
|
{aboutText}
|
|
</p>
|
|
)}
|
|
</div>
|
|
{aboutCta && aboutCta.label && aboutCta.url && (
|
|
<a
|
|
href={aboutCta.url}
|
|
target={aboutCta.newTab ? '_blank' : '_self'}
|
|
rel="noopener noreferrer"
|
|
className="self-start flex items-center gap-2 text-xs text-foreground/60 border border-foreground/10 rounded-lg px-5 py-2.5 hover:text-foreground/90 hover:bg-muted transition-colors"
|
|
>
|
|
<i className="ti ti-download" style={{ fontSize: 13 }} aria-hidden="true" />
|
|
{aboutCta.label}
|
|
</a>
|
|
)}
|
|
</div>
|
|
|
|
{/* Skills Section */}
|
|
<div className="bg-muted/50 border border-foreground/10 rounded-2xl p-8">
|
|
{skillsHeading && (
|
|
<p className="text-[10px] font-bold tracking-[0.2em] uppercase text-foreground/30 mb-6">
|
|
{skillsHeading}
|
|
</p>
|
|
)}
|
|
{Array.isArray(skills) && skills.length > 0 && (
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
|
{skills.map(function (skill, i) {
|
|
const tags = skill.tags
|
|
? skill.tags
|
|
.split(',')
|
|
.map((t) => t.trim())
|
|
.filter(Boolean)
|
|
: []
|
|
return (
|
|
<div
|
|
key={i}
|
|
className="bg-background/50 border border-foreground/10 rounded-xl p-4 flex flex-col gap-3"
|
|
>
|
|
<i
|
|
className={'ti ' + skill.icon + ' text-foreground/30'}
|
|
style={{ fontSize: 16 }}
|
|
aria-hidden="true"
|
|
/>
|
|
<p className="text-xs font-medium text-foreground/80">{skill.title}</p>
|
|
<div className="flex flex-wrap gap-1.5">
|
|
{tags.map(function (tag, j) {
|
|
return (
|
|
<span
|
|
key={j}
|
|
className="text-[10px] text-foreground/40 border border-foreground/5 rounded-full px-2 py-0.5"
|
|
>
|
|
{tag}
|
|
</span>
|
|
)
|
|
})}
|
|
</div>
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
)
|
|
}
|