changed names

This commit is contained in:
Mackie 2026-06-08 12:44:13 +08:00
parent 00d6016097
commit 832655c921
5 changed files with 276 additions and 2 deletions

View file

@ -0,0 +1,97 @@
'use client'
import React from 'react'
import { Container } from '@/components/ui/Container' // Ensure this path is correct
import type { Skill } from '@/payload-types' // Adjust import based on your project
type AboutProps = {
aboutHeading?: string
aboutText?: string
aboutCta?: { label?: string; url?: string; newTab?: boolean }
skillsHeading?: string
skills?: Skill[]
}
export function AboutBlock(props: AboutProps) {
const { aboutHeading, aboutText, aboutCta, skillsHeading, skills } = props
return (
// Replaced hardcoded max-w-5xl and section with the unified Container
<Container className="py-12 md:py-24">
<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-xs font-bold tracking-[0.2em] uppercase text-foreground/60 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-xs font-bold tracking-[0.2em] uppercase text-foreground/60 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>
</Container>
)
}

View file

@ -0,0 +1,50 @@
import type { Block } from 'payload'
export const AboutBlock: Block = {
slug: 'about',
labels: { singular: 'About (About + Skills)', plural: 'About' },
fields: [
{
name: 'aboutHeading',
type: 'text',
label: 'About heading',
},
{
name: 'aboutText',
type: 'textarea',
label: 'About text',
},
{
name: 'aboutCta',
type: 'group',
label: 'About CTA button',
fields: [
{ name: 'label', type: 'text', label: 'Label', defaultValue: 'Download CV' },
{ name: 'url', type: 'text', label: 'URL' },
{ name: 'newTab', type: 'checkbox', label: 'Open in new tab', defaultValue: true },
],
},
{
name: 'skillsHeading',
type: 'text',
label: 'Skills heading',
defaultValue: 'Expertise',
},
{
name: 'skills',
type: 'array',
label: 'Skill cards',
maxRows: 6,
fields: [
{
name: 'icon',
type: 'text',
label: 'Tabler icon name (e.g. ti-components)',
required: true,
},
{ name: 'title', type: 'text', label: 'Title', required: true },
{ name: 'tags', type: 'text', label: 'Tags (comma separated)', required: true },
],
},
],
}

View file

@ -0,0 +1,76 @@
'use client'
import React from 'react'
import { Container } from '@/components/ui/Container'
const colorMap: Record<string, { border: string; dot: string }> = {
gray: { border: 'border-t-[#888780]', dot: 'bg-[#888780]' },
blue: { border: 'border-t-[#378ADD]', dot: 'bg-[#378ADD]' },
green: { border: 'border-t-[#1D9E75]', dot: 'bg-[#1D9E75]' },
amber: { border: 'border-t-[#BA7517]', dot: 'bg-[#BA7517]' },
red: { border: 'border-t-[#E24B4A]', dot: 'bg-[#E24B4A]' },
purple: { border: 'border-t-[#7F77DD]', dot: 'bg-[#7F77DD]' },
teal: { border: 'border-t-[#1D9E75]', dot: 'bg-[#1D9E75]' },
}
type Card = { title: string; subtitle?: string }
type Column = { title: string; color?: string; cards?: Card[] }
type Props = { columns?: Column[] }
export function ProcessBlock({ columns }: Props) {
if (!Array.isArray(columns) || columns.length === 0) return null
return (
<Container className="py-12 md:py-24">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
{columns.map((col, i) => {
const { border, dot } = colorMap[col.color ?? 'gray'] ?? colorMap.gray
return (
<div
key={i}
// Added your custom class for the horizontal arrow
className={`column-with-connector bg-muted/50 rounded-2xl p-6 flex flex-col gap-4 border-t-[3px] ${border}`}
>
<div className="flex items-center gap-2 mb-2">
<span className={`w-2 h-2 rounded-full shrink-0 ${dot}`} />
<span className="text-xs font-bold tracking-[0.2em] uppercase text-foreground/60">
{col.title}
</span>
</div>
<div className="flex flex-col gap-3">
{col.cards?.map((card, j) => (
<React.Fragment key={j}>
<div className="bg-background/70 border border-foreground/5 rounded-xl px-4 py-3 flex flex-col gap-1">
<p className="text-sm font-medium text-foreground/80">{card.title}</p>
{card.subtitle && (
<p className="text-[11px] text-foreground/40">{card.subtitle}</p>
)}
</div>
{/* Vertical Connector Arrow */}
{j < (col.cards?.length || 0) - 1 && (
<div className="flex justify-center text-foreground/20">
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
>
<path d="M12 5v14M19 12l-7 7-7-7" />
</svg>
</div>
)}
</React.Fragment>
))}
</div>
</div>
)
})}
</div>
</Container>
)
}

View file

@ -0,0 +1,47 @@
// src/blocks/KanbanColor/config.ts
import type { Block } from 'payload'
export const ProcessBlock: Block = {
slug: 'process',
labels: { singular: 'Process', plural: 'Process' },
fields: [
{
name: 'columns',
type: 'array',
label: 'Columns',
minRows: 1,
fields: [
{
name: 'title',
type: 'text',
label: 'Column title',
required: true,
},
{
name: 'color',
type: 'select',
label: 'Accent color',
defaultValue: 'gray',
options: [
{ label: 'Gray', value: 'gray' },
{ label: 'Blue', value: 'blue' },
{ label: 'Green', value: 'green' },
{ label: 'Amber', value: 'amber' },
{ label: 'Red', value: 'red' },
{ label: 'Purple', value: 'purple' },
{ label: 'Teal', value: 'teal' },
],
},
{
name: 'cards',
type: 'array',
label: 'Cards',
fields: [
{ name: 'title', type: 'text', label: 'Title', required: true },
{ name: 'subtitle', type: 'text', label: 'Subtitle / Category' },
],
},
],
},
],
}

View file

@ -9,12 +9,14 @@ import { FormBlock } from '@/blocks/Form/Component'
import { MediaBlock } from '@/blocks/MediaBlock/Component'
import { SkillsBlock } from '@/blocks/Skills/Component'
import { SkillsMarqueeBlock } from '@/blocks/SkillsMarquee/Component'
import { KanbanColorBlock } from '@/blocks/KanbanColor/Component'
import { ProcessBlock } from '@/blocks/Process/Component'
import { KanbanColor } from '@/blocks/KanbanColor/Component'
import { KanbanHoriBlock } from '@/blocks/KanbanHori/Component'
import { ShowcaseBlock } from '@/blocks/Showcase/Component'
import { AboutProfileBlock } from '@/blocks/AboutProfile/Component'
import { StatsStripBlock } from '@/blocks/StatsStrip/Component'
import { BentoRowBlock } from '@/blocks/BentoRow/Component'
import { AboutBlock } from '@/blocks/About/Component'
import { BentoRow } from '@/blocks/BentoRow/Component'
import { ContactBlock } from '@/blocks/Contact/Component'
import { ToolStackBlock } from '@/blocks/ToolStack/Component'
@ -26,6 +28,8 @@ const blockComponents = {
mediaBlock: MediaBlock,
skills: SkillsBlock,
skillsMarquee: SkillsMarqueeBlock,
about: AboutBlock,
process: ProcessBlock,
kanbanColor: KanbanColorBlock,
kanbanHori: KanbanHoriBlock,
showcase: ShowcaseBlock,