kanban / src /components /templates /creative /sections /ProjectSection.tsx
Leon4gr45's picture
Deploy magic-resume as Docker Space (port 3000)
c30ea2a verified
Raw
History Blame Contribute Delete
4.6 kB
import React from "react";
import { motion, AnimatePresence } from "framer-motion";
import SectionTitle from "./SectionTitle";
import SectionWrapper from "../../shared/SectionWrapper";
import { Project, GlobalSettings } from "@/types/resume";
import { normalizeRichTextContent } from "@/lib/richText";
import { formatDateString } from "@/lib/utils";
import { useLocale } from "@/i18n/compat/client";
import { getProjectLinkMeta } from "@/lib/projectLink";
interface ProjectSectionProps {
projects: Project[];
globalSettings?: GlobalSettings;
showTitle?: boolean;
}
const ProjectSection: React.FC<ProjectSectionProps> = ({ projects, globalSettings, showTitle = true }) => {
const locale = useLocale();
const visibleProjects = projects?.filter((p) => p.visible);
const centerSubtitle = globalSettings?.centerSubtitle;
const flexLayout = globalSettings?.flexibleHeaderLayout;
return (
<SectionWrapper sectionId="projects" style={{ marginTop: `${globalSettings?.sectionSpacing || 24}px` }}>
<SectionTitle type="projects" globalSettings={globalSettings} showTitle={showTitle} />
<motion.div layout="position">
<AnimatePresence mode="popLayout">
{visibleProjects.map((project) => {
const projectLink = getProjectLinkMeta(project, {
preferFullUrl: centerSubtitle,
});
return (
<motion.div key={project.id} style={{ marginTop: `${globalSettings?.paragraphSpacing}px` }}>
<motion.div className="flex items-center gap-2">
<div className={`flex items-center gap-2 ${flexLayout ? "" : "flex-[1.5]"}`}>
<h3 className="font-bold" style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>{project.name}</h3>
</div>
{projectLink && !centerSubtitle && (
<a href={projectLink.href} target="_blank" rel="noopener noreferrer"
className={`underline ${flexLayout ? "" : "flex-1"}`} title={projectLink.title} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
{projectLink.label}
</a>
)}
{!projectLink && !centerSubtitle && !flexLayout && <div className="flex-1" />}
{centerSubtitle && (
<motion.div layout="position" className={`text-subtitleFont ${flexLayout ? "ml-[16px]" : "flex-1"}`} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
{project.role}
</motion.div>
)}
<div className={`text-subtitleFont shrink-0 ${flexLayout ? "ml-auto" : "flex-1 text-right"}`} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>
{formatDateString(project.date, locale)}
</div>
</motion.div>
{project.role && !centerSubtitle && (
<motion.div layout="position" className="text-subtitleFont" style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>{project.role}</motion.div>
)}
{projectLink && centerSubtitle && (
<a href={projectLink.href} target="_blank" rel="noopener noreferrer" className="underline" title={projectLink.title} style={{ fontSize: `${globalSettings?.subheaderSize || 16}px` }}>{projectLink.label}</a>
)}
{project.description && (
<motion.div layout="position" className="mt-1 text-baseFont"
style={{ fontSize: `${globalSettings?.baseFontSize || 14}px`, lineHeight: globalSettings?.lineHeight || 1.6 }}
dangerouslySetInnerHTML={{ __html: normalizeRichTextContent(project.description) }}
/>
)}
</motion.div>
)})}
</AnimatePresence>
</motion.div>
</SectionWrapper>
);
};
export default ProjectSection;