@@ -16,6 +16,9 @@ import {
1616 CheckCircle2 ,
1717 ArrowRight ,
1818 ChevronRight ,
19+ GitCommitHorizontal ,
20+ Upload ,
21+ GitPullRequestArrow ,
1922} from "lucide-react" ;
2023import type { LucideIcon } from "lucide-react" ;
2124import { useTranslations } from "next-intl" ;
@@ -27,21 +30,26 @@ const prismColors = ["#22d3ee", "#a78bfa", "#fb7185", "#fbbf24"] as const;
2730const colorAt = ( i : number ) => prismColors [ i % prismColors . length ] ;
2831
2932/* ── Step data ── */
33+ type TerminalData = {
34+ label : string ;
35+ lines : { prompt ?: boolean ; text : string ; accent ?: string } [ ] ;
36+ } ;
37+
38+ type SubStepData = {
39+ label : string ;
40+ terminal : TerminalData ;
41+ } ;
42+
3043type StepData = {
3144 title : string ;
3245 description : string ;
3346 icon : LucideIcon ;
34- terminal : {
35- label : string ;
36- lines : { prompt ?: boolean ; text : string ; accent ?: string } [ ] ;
37- } ;
47+ terminal : TerminalData ;
3848 optionToggle ?: {
3949 labels : [ string , string ] ;
40- terminals : [
41- { label : string ; lines : { prompt ?: boolean ; text : string ; accent ?: string } [ ] } ,
42- { label : string ; lines : { prompt ?: boolean ; text : string ; accent ?: string } [ ] } ,
43- ] ;
50+ terminals : [ TerminalData , TerminalData ] ;
4451 } ;
52+ subSteps ?: SubStepData [ ] ;
4553} ;
4654
4755// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -198,6 +206,108 @@ const getSteps = (t: any): StepData[] => [
198206 ] ,
199207 } ,
200208 } ,
209+ {
210+ title : t ( "step9Title" ) ,
211+ description : t ( "step9Desc" ) ,
212+ icon : GitCommitHorizontal ,
213+ terminal : { label : "terminal" , lines : [ ] } ,
214+ subSteps : [
215+ {
216+ label : t ( "step9Sub1" ) ,
217+ terminal : {
218+ label : "terminal" ,
219+ lines : [
220+ { prompt : true , text : "git add content/profile/your_name.mdx" } ,
221+ ] ,
222+ } ,
223+ } ,
224+ {
225+ label : t ( "step9Sub2" ) ,
226+ terminal : {
227+ label : "terminal" ,
228+ lines : [
229+ { prompt : true , text : "bun commit" } ,
230+ { text : "? Select the type of change:" , accent : "#a78bfa" } ,
231+ ] ,
232+ } ,
233+ } ,
234+ {
235+ label : t ( "step9Sub3" ) ,
236+ terminal : {
237+ label : "gitmoji interactive" ,
238+ lines : [
239+ { text : "? Choose a gitmoji: :fire: build" , accent : "#fbbf24" } ,
240+ { text : "? Choose the type: build" , accent : "#22d3ee" } ,
241+ { text : "? Scope: profile" } ,
242+ { text : '? Message: add your_name profile' , accent : "#fb7185" } ,
243+ ] ,
244+ } ,
245+ } ,
246+ {
247+ label : t ( "step9Sub4" ) ,
248+ terminal : {
249+ label : "terminal" ,
250+ lines : [
251+ { text : ":fire: build(profile): add your_name profile" , accent : "#22d3ee" } ,
252+ { text : "1 file changed, 12 insertions(+)" } ,
253+ ] ,
254+ } ,
255+ } ,
256+ ] ,
257+ } ,
258+ {
259+ title : t ( "step10Title" ) ,
260+ description : t ( "step10Desc" ) ,
261+ icon : Upload ,
262+ terminal : {
263+ label : "terminal" ,
264+ lines : [
265+ { prompt : true , text : "git push origin your_name" } ,
266+ { text : "Enumerating objects: 5, done." , accent : "#a78bfa" } ,
267+ { text : "Writing objects: 100% (3/3), done." } ,
268+ { text : "remote: Create a pull request for 'your_name' on GitHub by visiting:" , accent : "#fb7185" } ,
269+ { text : "remote: https://github.com/YOUR_USERNAME/...github.io/pull/new/your_name" } ,
270+ ] ,
271+ } ,
272+ } ,
273+ {
274+ title : t ( "step11Title" ) ,
275+ description : t ( "step11Desc" ) ,
276+ icon : GitPullRequestArrow ,
277+ terminal : { label : "github.com" , lines : [ ] } ,
278+ subSteps : [
279+ {
280+ label : t ( "step11Sub1" ) ,
281+ terminal : {
282+ label : "github.com" ,
283+ lines : [
284+ { text : t ( "step11Line1" ) , accent : "#fbbf24" } ,
285+ { text : "" } ,
286+ { text : t ( "step11Line2" ) } ,
287+ ] ,
288+ } ,
289+ } ,
290+ {
291+ label : t ( "step11Sub2" ) ,
292+ terminal : {
293+ label : "github.com — pull request" ,
294+ lines : [
295+ { text : t ( "step11Line3" ) , accent : "#22d3ee" } ,
296+ { text : t ( "step11Line4" ) } ,
297+ ] ,
298+ } ,
299+ } ,
300+ {
301+ label : t ( "step11Sub3" ) ,
302+ terminal : {
303+ label : "github.com" ,
304+ lines : [
305+ { text : t ( "step11Line5" ) , accent : "#fb7185" } ,
306+ ] ,
307+ } ,
308+ } ,
309+ ] ,
310+ } ,
201311] ;
202312
203313/* ── Hero Section ── */
@@ -358,6 +468,143 @@ const TerminalBlock = ({
358468 </ motion . div >
359469) ;
360470
471+ /* ── Sub-Steps Block ── */
472+ const subStepLetters = "abcdefghijklmnopqrstuvwxyz" ;
473+
474+ const SubStepsBlock = ( {
475+ subSteps,
476+ color,
477+ isInView,
478+ mmFont = "" ,
479+ } : {
480+ subSteps : SubStepData [ ] ;
481+ color : string ;
482+ isInView : boolean ;
483+ mmFont ?: string ;
484+ } ) => (
485+ < div className = "space-y-0" >
486+ { subSteps . map ( ( sub , i ) => {
487+ const isLast = i === subSteps . length - 1 ;
488+ return (
489+ < div key = { i } className = "flex gap-3" >
490+ { /* Sub-step indicator: letter + connecting line */ }
491+ < div className = "flex flex-col items-center shrink-0 pt-1" >
492+ < motion . div
493+ className = "relative flex items-center justify-center w-6 h-6 rounded-full z-10"
494+ style = { {
495+ background : `linear-gradient(135deg, ${ color } 14, ${ color } 06)` ,
496+ border : `1.5px solid ${ color } 30` ,
497+ } }
498+ initial = { { scale : 0 , opacity : 0 } }
499+ animate = {
500+ isInView
501+ ? { scale : 1 , opacity : 1 }
502+ : { scale : 0 , opacity : 0 }
503+ }
504+ transition = { {
505+ type : "spring" ,
506+ stiffness : 300 ,
507+ damping : 20 ,
508+ delay : 0.2 + i * 0.1 ,
509+ } }
510+ >
511+ < span
512+ className = "font-mono text-[10px] font-bold"
513+ style = { { color } }
514+ >
515+ { subStepLetters [ i ] }
516+ </ span >
517+ </ motion . div >
518+ { ! isLast && (
519+ < motion . div
520+ className = "w-[1.5px] flex-1 min-h-[12px] origin-top"
521+ style = { {
522+ background : `linear-gradient(180deg, ${ color } 25, ${ color } 08)` ,
523+ } }
524+ initial = { { scaleY : 0 } }
525+ animate = { isInView ? { scaleY : 1 } : { scaleY : 0 } }
526+ transition = { {
527+ duration : 0.4 ,
528+ delay : 0.35 + i * 0.1 ,
529+ ease : [ 0.22 , 1 , 0.36 , 1 ] ,
530+ } }
531+ />
532+ ) }
533+ </ div >
534+
535+ { /* Sub-step content */ }
536+ < motion . div
537+ className = { cn ( "flex-1" , isLast ? "" : "pb-3" ) }
538+ initial = { { opacity : 0 , x : - 8 } }
539+ animate = {
540+ isInView ? { opacity : 1 , x : 0 } : { opacity : 0 , x : - 8 }
541+ }
542+ transition = { {
543+ duration : 0.4 ,
544+ delay : 0.25 + i * 0.1 ,
545+ ease : [ 0.22 , 1 , 0.36 , 1 ] ,
546+ } }
547+ >
548+ { /* Sub-step label */ }
549+ < p
550+ className = { cn (
551+ "font-mono text-[11px] text-zinc-500 mb-1.5 tracking-wide" ,
552+ mmFont
553+ ) }
554+ >
555+ { sub . label }
556+ </ p >
557+ { /* Mini terminal */ }
558+ < div
559+ className = { cn (
560+ "rounded-xl overflow-hidden" ,
561+ "bg-surface/60 backdrop-blur-sm" ,
562+ "border border-white/[0.04]"
563+ ) }
564+ >
565+ < div className = "flex items-center gap-1.5 px-3 py-1.5 border-b border-white/[0.03]" >
566+ < div className = "flex gap-1" >
567+ < div className = "w-1.5 h-1.5 rounded-full bg-prism-rose/40" />
568+ < div className = "w-1.5 h-1.5 rounded-full bg-accent-gold/40" />
569+ < div className = "w-1.5 h-1.5 rounded-full bg-prism-cyan/40" />
570+ </ div >
571+ < span className = "font-mono text-[9px] text-zinc-600 ml-0.5" >
572+ { sub . terminal . label }
573+ </ span >
574+ </ div >
575+ < div className = "px-3 py-2.5 space-y-0.5" >
576+ { sub . terminal . lines . map ( ( line , j ) => (
577+ < div key = { j } className = "flex items-start gap-1.5" >
578+ { line . prompt && (
579+ < span
580+ className = "font-mono text-[11px] shrink-0"
581+ style = { { color : `${ color } 80` } }
582+ >
583+ $
584+ </ span >
585+ ) }
586+ < span
587+ className = { cn (
588+ "font-mono text-[11px] leading-relaxed break-all" ,
589+ line . accent ? "" : "text-zinc-400"
590+ ) }
591+ style = {
592+ line . accent ? { color : line . accent } : undefined
593+ }
594+ >
595+ { line . text || "\u00A0" }
596+ </ span >
597+ </ div >
598+ ) ) }
599+ </ div >
600+ </ div >
601+ </ motion . div >
602+ </ div >
603+ ) ;
604+ } ) }
605+ </ div >
606+ ) ;
607+
361608/* ── Option Toggle for Step 7 ── */
362609const OptionToggle = ( {
363610 labels,
@@ -527,8 +774,15 @@ const StepCard = ({
527774 />
528775 ) }
529776
530- { /* Terminal block */ }
531- { step . optionToggle ? (
777+ { /* Terminal / Sub-steps / Option toggle */ }
778+ { step . subSteps ? (
779+ < SubStepsBlock
780+ subSteps = { step . subSteps }
781+ color = { color }
782+ isInView = { inView }
783+ mmFont = { mmFont }
784+ />
785+ ) : step . optionToggle ? (
532786 < AnimatePresence mode = "wait" >
533787 < motion . div
534788 key = { activeOption }
0 commit comments