import ReactMarkdown from 'react-markdown'; import Card from 'react-bootstrap/Card'; import { type CvSectionConfig, type GistFile } from '../../api/cv'; import { entryAnchorId } from '../../lib/cvDates'; interface Props { section: CvSectionConfig; files: GistFile[]; } // Pipe-delimited fields (e.g. "email | phone | github, linkedin" in the // contact section) become one paragraph per field, so each lands on its own // line with a paragraph gap. Within each pipe-segment, comma-separated values // are stacked with a soft line break (markdown ` \n` -> `
`) so multiple // emails / phones / urls each get their own line at a tighter spacing. function splitPipes(content: string): string { return content .split('\n') .map((line) => { if (!line.includes(' | ')) return line; return line .split(' | ') .map((segment) => segment.includes(', ') ? segment.split(', ').join(' \n') : segment, ) .join('\n\n'); }) .join('\n'); } // Renders a single section. Each .md file becomes its own block. When // `show_section_name` is true (e.g. experience, education) the entries are // wrapped in cards and given anchor ids so the timeline sidebar can deep-link // to them; otherwise (e.g. summary, contact) they render as flat markdown. export function CvSection({ section, files }: Props) { return (
{section.show_section_name &&

{section.name}

} {files.map((file) => { const content = section.show_section_name ? file.content : splitPipes(file.content); if (section.show_section_name) { return (
{content}
); } return (
{content}
); })}
); }