Logo of Sweep
[Feat] - Add `react-flow` as blue print on viewing detailed projecturquico/portfolio#60

> > >

✓ Completed in 45 minutes, 2 months ago using GPT-4  •   Book a call  •   Report a bug


Progress

  Modifysrc/lib/types.ts 2edaaf0 
1import { ReactNode } from 'react';
2
3export type Testimonial = {
4  name: string;
5  role: string;
6  quote: string;
7  image: string;
8  date: string;
9};
10
11export type ExperienceData = {
12  title: string;
13  date: string;
14  location: string;
15  description: string[];
16  active: boolean;
17  projects: string[];
18};
19
20export type StackData = {
21  label: string;
22  src: string;
23};
24
25export type LinksType = {
26  label: string;
27  path: string;
28};
29
30export type SocialsType = {
31  label: string;
32  path: string;
33  icon: ReactNode;
34};
35
36export type MaintenanceMessage = {
37  emoji: string;
38  title: string;
39  subtitle: string;
40  description: string;
41};
42
43export type ProjectData = {
44  title: string;
45  date: string;
46  client: string;
47  description: string[];
48  isInProgress: boolean;
49  associatedExperience: string;
50  role: string;
51  stacks: {
52    label: string;
53    src: string;
54  }[];
55  githubLink?: string;
56  previewLink?: string;
57};
58

In the ProjectData type, add a new optional property: reactFlowData?: any; This will allow associating react-flow diagram data with each project.

  Modifysrc/app/me/projects/main-project-timeline.tsx 2edaaf0 
1import CustomTimeline from '@/components/custom-timeline';
2import { ProjectData } from '@/lib/types';
3
4function MainProjectTimeline({ projectData }: { projectData: ProjectData[] }) {
5  return <CustomTimeline projectData={projectData} />;
6}
7
8export default MainProjectTimeline;
9

In the projectData prop being passed to CustomTimeline, ensure each project object includes the new reactFlowData property with the necessary react-flow diagram data.

  Modifysrc/components/custom-timeline.tsx 2edaaf0 
1'use client';
2
3import { TimelineType } from '@/lib/interfaces';
4import { Anchor, Avatar, Badge, Text, Timeline, Tooltip } from '@mantine/core';
5import {
6  IconActivityHeartbeat,
7  IconBrandGithub,
8  IconCheck,
9  IconError404,
10  IconLink,
11} from '@tabler/icons-react';
12
13import CustomButton from './custom-button';
14
15function CustomTimeline({ experienceData, projectData }: TimelineType) {
16  if (experienceData) {
17    return (
18      <Timeline
19        active={4}
20        bulletSize={24}
21        lineWidth={4}
22        color='dark'
23        className='w-[40rem] px-12 py-4 max-md:w-full flex flex-col gap-4 mt-4'
24      >
25        {experienceData?.map((experience, index) => (
26          <Timeline.Item
27            key={index}
28            bullet={
29              experience.active ? (
30                <IconActivityHeartbeat size={12} />
31              ) : (
32                <IconCheck size={12} />
33              )
34            }
35            title={
36              <Text className='text-white text-lg font-bold'>
37                {experience.title}
38              </Text>
39            }
40          >
41            <Text c='dimmed' size='sm' fw='bold'>
42              {experience.date}
43            </Text>
44            <Text size='xs' mt={4} className='text-zinc-200 mb-4' c='dimmed'>
45              {experience.location}
46            </Text>
47            <div className='flex flex-col gap-2'>
48              {experience.description.map((desc, i) => (
49                <Text key={i} c='dimmed' size='sm' className='text-justify'>
50                  {desc}
51                </Text>
52              ))}
53
54              {experience.projects.length > 0 && (
55                <Text className='text-white' fz='xs' fw='bold'>
56                  Associated Projects:
57                </Text>
58              )}
59              <div className='flex gap-2'>
60                {experience.projects.map((project, i) => (
61                  <Badge key={i} color='dark'>
62                    {project}
63                  </Badge>
64                ))}
65              </div>
66            </div>
67          </Timeline.Item>
68        ))}
69      </Timeline>
70    );
71  }
72
73  return (
74    <Timeline
75      active={4}
76      bulletSize={24}
77      lineWidth={4}
78      color='dark'
79      className='w-[40rem] px-12 py-4 max-md:w-full flex flex-col gap-4 mt-4'
80    >
81      {projectData?.map((project, index) => (
82        <Timeline.Item
83          key={index}
84          bullet={
85            project.isInProgress ? (
86              <IconActivityHeartbeat size={12} />
87            ) : (
88              <IconCheck size={12} />
89            )
90          }
91          title={
92            <>
93              {project.previewLink ? (
94                <Anchor
95                  href={project.previewLink}
96                  target='_blank'
97                  className='text-white text-lg font-bold hover:underline cursor-pointer'
98                >
99                  {project.title} <IconLink size='1rem' />
100                </Anchor>
101              ) : (
102                <Text className='text-white text-lg font-bold'>
103                  {project.title}
104                </Text>
105              )}
106            </>
107          }
108        >
109          <Text className='text-white' fz='xs' fw='bold'>
110            {project.role}
111          </Text>
112
113          <Text c='dimmed' size='sm' fw='bold'>
114            {project.date}
115          </Text>
116          <Text size='xs' mt={4} className='text-zinc-200 mb-4' c='dimmed'>
117            {project.client}
118          </Text>
119          <div className='flex flex-col gap-2'>
120            {project.description.map((desc, i) => (
121              <Text key={i} c='dimmed' size='sm' className='text-justify'>
122                {desc}
123              </Text>
124            ))}
125
126            <Tooltip.Group openDelay={300} closeDelay={100}>
127              <Avatar.Group spacing='xs'>
128                {project.stacks.map((stack, i) => (
129                  <Tooltip label={stack.label} withArrow key={i}>
130                    <Avatar src={stack.src} radius='xl' size='md'>
131                      <IconError404 size='1.5rem' />
132                    </Avatar>
133                  </Tooltip>
134                ))}
135              </Avatar.Group>
136            </Tooltip.Group>
137
138            {project.associatedExperience.length > 0 && (
139              <Text className='text-white' fz='xs' fw='bold' c='dimmed'>
140                Associated with {project.associatedExperience}
141              </Text>
142            )}
143          </div>
144
145          {project.githubLink && (
146            <CustomButton
147              icon={<IconBrandGithub size={14} />}
148              path={project.githubLink}
149              label='View Repository'
150              className='mt-4'
151              size='xs'
152            />
153          )}
154        </Timeline.Item>
155      ))}
156    </Timeline>
157  );
158}
159
160export default CustomTimeline;
161

Import the necessary react-flow components at the top: import ReactFlow from 'reactflow'; import 'reactflow/dist/style.css';

In the JSX for each project Timeline.Item, add a new "View Details" button: <CustomButton label="View Details" className="mt-4" size="xs" onClick={() => openDetails(project)} />

Implement the openDetails function to display the react-flow diagram in a modal when clicked: const openDetails = (project) => { // Open a modal and render the react-flow diagram // Pass the project.reactFlowData to the ReactFlow component // Example: <Modal opened={opened} onClose={close}> <ReactFlow elements={project.reactFlowData} /> </Modal> }

Plan

This is based on the results of the Planning step. The plan may expand from failed GitHub Actions runs.

Code Snippets Found

This is based on the results of the Searching step.

src/lib/types.ts:0-58 
1import { ReactNode } from 'react';
2
3export type Testimonial = {
4  name: string;
5  role: string;
6  quote: string;
7  image: string;
8  date: string;
9};
10
11export type ExperienceData = {
12  title: string;
13  date: string;
14  location: string;
15  description: string[];
16  active: boolean;
17  projects: string[];
18};
19
20export type StackData = {
21  label: string;
22  src: string;
23};
24
25export type LinksType = {
26  label: string;
27  path: string;
28};
29
30export type SocialsType = {
31  label: string;
32  path: string;
33  icon: ReactNode;
34};
35
36export type MaintenanceMessage = {
37  emoji: string;
38  title: string;
39  subtitle: string;
40  description: string;
41};
42
43export type ProjectData = {
44  title: string;
45  date: string;
46  client: string;
47  description: string[];
48  isInProgress: boolean;
49  associatedExperience: string;
50  role: string;
51  stacks: {
52    label: string;
53    src: string;
54  }[];
55  githubLink?: string;
56  previewLink?: string;
57};
58
src/app/me/projects/main-project-timeline.tsx:0-9 
1import CustomTimeline from '@/components/custom-timeline';
2import { ProjectData } from '@/lib/types';
3
4function MainProjectTimeline({ projectData }: { projectData: ProjectData[] }) {
5  return <CustomTimeline projectData={projectData} />;
6}
7
8export default MainProjectTimeline;
9
src/components/custom-timeline.tsx:0-161 
1'use client';
2
3import { TimelineType } from '@/lib/interfaces';
4import { Anchor, Avatar, Badge, Text, Timeline, Tooltip } from '@mantine/core';
5import {
6  IconActivityHeartbeat,
7  IconBrandGithub,
8  IconCheck,
9  IconError404,
10  IconLink,
11} from '@tabler/icons-react';
12
13import CustomButton from './custom-button';
14
15function CustomTimeline({ experienceData, projectData }: TimelineType) {
16  if (experienceData) {
17    return (
18      <Timeline
19        active={4}
20        bulletSize={24}
21        lineWidth={4}
22        color='dark'
23        className='w-[40rem] px-12 py-4 max-md:w-full flex flex-col gap-4 mt-4'
24      >
25        {experienceData?.map((experience, index) => (
26          <Timeline.Item
27            key={index}
28            bullet={
29              experience.active ? (
30                <IconActivityHeartbeat size={12} />
31              ) : (
32                <IconCheck size={12} />
33              )
34            }
35            title={
36              <Text className='text-white text-lg font-bold'>
37                {experience.title}
38              </Text>
39            }
40          >
41            <Text c='dimmed' size='sm' fw='bold'>
42              {experience.date}
43            </Text>
44            <Text size='xs' mt={4} className='text-zinc-200 mb-4' c='dimmed'>
45              {experience.location}
46            </Text>
47            <div className='flex flex-col gap-2'>
48              {experience.description.map((desc, i) => (
49                <Text key={i} c='dimmed' size='sm' className='text-justify'>
50                  {desc}
51                </Text>
52              ))}
53
54              {experience.projects.length > 0 && (
55                <Text className='text-white' fz='xs' fw='bold'>
56                  Associated Projects:
57                </Text>
58              )}
59              <div className='flex gap-2'>
60                {experience.projects.map((project, i) => (
61                  <Badge key={i} color='dark'>
62                    {project}
63                  </Badge>
64                ))}
65              </div>
66            </div>
67          </Timeline.Item>
68        ))}
69      </Timeline>
70    );
71  }
72
73  return (
74    <Timeline
75      active={4}
76      bulletSize={24}
77      lineWidth={4}
78      color='dark'
79      className='w-[40rem] px-12 py-4 max-md:w-full flex flex-col gap-4 mt-4'
80    >
81      {projectData?.map((project, index) => (
82        <Timeline.Item
83          key={index}
84          bullet={
85            project.isInProgress ? (
86              <IconActivityHeartbeat size={12} />
87            ) : (
88              <IconCheck size={12} />
89            )
90          }
91          title={
92            <>
93              {project.previewLink ? (
94                <Anchor
95                  href={project.previewLink}
96                  target='_blank'
97                  className='text-white text-lg font-bold hover:underline cursor-pointer'
98                >
99                  {project.title} <IconLink size='1rem' />
100                </Anchor>
101              ) : (
102                <Text className='text-white text-lg font-bold'>
103                  {project.title}
104                </Text>
105              )}
106            </>
107          }
108        >
109          <Text className='text-white' fz='xs' fw='bold'>
110            {project.role}
111          </Text>
112
113          <Text c='dimmed' size='sm' fw='bold'>
114            {project.date}
115          </Text>
116          <Text size='xs' mt={4} className='text-zinc-200 mb-4' c='dimmed'>
117            {project.client}
118          </Text>
119          <div className='flex flex-col gap-2'>
120            {project.description.map((desc, i) => (
121              <Text key={i} c='dimmed' size='sm' className='text-justify'>
122                {desc}
123              </Text>
124            ))}
125
126            <Tooltip.Group openDelay={300} closeDelay={100}>
127              <Avatar.Group spacing='xs'>
128                {project.stacks.map((stack, i) => (
129                  <Tooltip label={stack.label} withArrow key={i}>
130                    <Avatar src={stack.src} radius='xl' size='md'>
131                      <IconError404 size='1.5rem' />
132                    </Avatar>
133                  </Tooltip>
134                ))}
135              </Avatar.Group>
136            </Tooltip.Group>
137
138            {project.associatedExperience.length > 0 && (
139              <Text className='text-white' fz='xs' fw='bold' c='dimmed'>
140                Associated with {project.associatedExperience}
141              </Text>
142            )}
143          </div>
144
145          {project.githubLink && (
146            <CustomButton
147              icon={<IconBrandGithub size={14} />}
148              path={project.githubLink}
149              label='View Repository'
150              className='mt-4'
151              size='xs'
152            />
153          )}
154        </Timeline.Item>
155      ))}
156    </Timeline>
157  );
158}
159
160export default CustomTimeline;
161