This commit is contained in:
Mackie 2026-05-25 03:15:30 +08:00
parent 7dc7c9720b
commit e7095aaa66
3 changed files with 153 additions and 1 deletions

View file

@ -0,0 +1,80 @@
import React from 'react'
import { cn } from '@/utilities/ui'
type SkillCategory = {
title: string
icon: string
tags: { tag: string }[]
}
type SkillsBlockProps = {
heading?: string
keySkills?: { skill: string }[]
categories?: SkillCategory[]
}
export function SkillsBlock({ heading, keySkills, categories }: SkillsBlockProps) {
return (
<section className="w-full px-6 py-16">
{/* Heading */}
{heading && (
<p className="text-center text-xs tracking-widest uppercase text-white/30 mb-6">
{heading}
</p>
)}
{/* Key skills pills */}
{Array.isArray(keySkills) && keySkills.length > 0 && (
<div className="flex justify-center gap-3 flex-wrap mb-12">
{keySkills.map(({ skill }, i) => (
<span
key={i}
className="text-xs text-white/70 border border-white/25 rounded-full px-4 py-1.5"
>
{skill}
</span>
))}
</div>
)}
{/* Categories grid */}
{Array.isArray(categories) && categories.length > 0 && (
<div
className="border border-white/8 rounded-xl overflow-hidden"
style={{
display: 'grid',
gridTemplateColumns: 'repeat(3, 1fr)',
}}
>
{categories.map((cat, i) => {
const isLastRow = i >= categories.length - (categories.length % 3 || 3)
const isLastCol = (i + 1) % 3 === 0
return (
<div
key={i}
className={cn(
'p-6 flex flex-col gap-3',
!isLastCol && 'border-r border-white/8',
!isLastRow && 'border-b border-white/8',
)}
>
<i className={`ti ${cat.icon} text-white/40`} style={{ fontSize: 20 }} aria-hidden="true" />
<p className="text-sm font-medium text-white/85">{cat.title}</p>
<div className="flex flex-wrap gap-1.5">
{Array.isArray(cat.tags) && cat.tags.map(({ tag }, j) => (
<span
key={j}
className="text-xs text-white/35 border border-white/10 rounded-full px-2.5 py-0.5"
>
{tag}
</span>
))}
</div>
</div>
)
})}
</div>
)}
</section>
)
}

View file

@ -0,0 +1,71 @@
import type { Block } from 'payload'
export const SkillsBlock: Block = {
slug: 'skills',
labels: {
singular: 'Skills Section',
plural: 'Skills Sections',
},
fields: [
{
name: 'heading',
type: 'text',
defaultValue: 'what i bring to the table',
},
{
name: 'keySkills',
type: 'array',
label: 'Key skills (pills at top)',
fields: [
{
name: 'skill',
type: 'text',
required: true,
},
],
},
{
name: 'categories',
type: 'array',
label: 'Skill categories',
fields: [
{
name: 'title',
type: 'text',
required: true,
},
{
name: 'icon',
type: 'select',
label: 'Icon (Tabler icon name)',
defaultValue: 'ti-layout',
options: [
{ label: 'Layout', value: 'ti-layout' },
{ label: 'Server', value: 'ti-server' },
{ label: 'Design / Pen', value: 'ti-vector-pen' },
{ label: 'Briefcase', value: 'ti-briefcase' },
{ label: 'Globe', value: 'ti-world' },
{ label: 'Camera', value: 'ti-camera' },
{ label: 'Tools', value: 'ti-tools' },
{ label: 'Sparkles', value: 'ti-sparkles' },
{ label: 'Mobile', value: 'ti-device-mobile' },
{ label: 'Code', value: 'ti-code' },
{ label: 'Chart', value: 'ti-chart-bar' },
{ label: 'Star', value: 'ti-star' },
],
},
{
name: 'tags',
type: 'array',
fields: [
{
name: 'tag',
type: 'text',
required: true,
},
],
},
],
},
],
}

View file

@ -7,6 +7,7 @@ import { CallToAction } from '../../blocks/CallToAction/config'
import { Content } from '../../blocks/Content/config'
import { FormBlock } from '../../blocks/Form/config'
import { MediaBlock } from '../../blocks/MediaBlock/config'
import { SkillsBlock } from '../../blocks/Skills/config'
import { hero } from '@/heros/config'
import { slugField } from 'payload'
import { populatePublishedAt } from '../../hooks/populatePublishedAt'
@ -72,7 +73,7 @@ export const Pages: CollectionConfig<'pages'> = {
{
name: 'layout',
type: 'blocks',
blocks: [CallToAction, Content, MediaBlock, Archive, FormBlock],
blocks: [CallToAction, Content, MediaBlock, Archive, FormBlock, SkillsBlock],
required: true,
admin: {
initCollapsed: true,