jsonresume-theme-clinical-precision 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/Resume.jsx ADDED
@@ -0,0 +1,764 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+ import {
4
+ Section,
5
+ SectionTitle,
6
+ DateRange,
7
+ Badge,
8
+ BadgeList,
9
+ ContactInfo,
10
+ Link,
11
+ safeUrl,
12
+ } from '@jsonresume/core';
13
+
14
+ /*
15
+ * CLINICAL PRECISION
16
+ * Vibe: clean, clinical, calm — a medical chart record.
17
+ * Layout: single column. Each entry is a "chart row": a green-railed
18
+ * left vital column (monospaced date code + location) and a content
19
+ * column on the right. Section titles carry a monospace "chart code".
20
+ * Type: IBM Plex Sans body, IBM Plex Mono for codes/metadata.
21
+ * Color: clinical green #059669, deep ink #0f2a25, mint tints, gray meta.
22
+ */
23
+
24
+ const GREEN = '#059669';
25
+ const GREEN_DARK = '#047857';
26
+ const INK = '#0f2a25';
27
+ const BODY = '#26433d';
28
+ const META = '#5b746e';
29
+ const MINT = '#f0fdf9';
30
+ const MINT_LINE = '#cdeee2';
31
+ const HAIR = '#dfeae6';
32
+
33
+ const Layout = styled.div`
34
+ max-width: 840px;
35
+ margin: 0 auto;
36
+ padding: 56px 52px 72px;
37
+ background: #ffffff;
38
+ font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, sans-serif;
39
+ color: ${BODY};
40
+ font-size: 14.5px;
41
+ line-height: 1.6;
42
+
43
+ @media print {
44
+ padding: 32px 28px;
45
+ }
46
+ `;
47
+
48
+ /* ---- header: the chart band ---- */
49
+ const Header = styled.header`
50
+ margin-bottom: 38px;
51
+ `;
52
+
53
+ const ChartRule = styled.div`
54
+ height: 6px;
55
+ background: ${GREEN};
56
+ border-radius: 3px;
57
+ margin-bottom: 18px;
58
+ `;
59
+
60
+ const ChartTop = styled.div`
61
+ display: flex;
62
+ justify-content: space-between;
63
+ align-items: baseline;
64
+ gap: 16px;
65
+ flex-wrap: wrap;
66
+ `;
67
+
68
+ const Name = styled.h1`
69
+ font-size: 38px;
70
+ font-weight: 700;
71
+ letter-spacing: -0.6px;
72
+ margin: 0;
73
+ color: ${INK};
74
+ `;
75
+
76
+ const RecordCode = styled.div`
77
+ font-family: 'IBM Plex Mono', monospace;
78
+ font-size: 11px;
79
+ letter-spacing: 0.5px;
80
+ color: ${META};
81
+ text-align: right;
82
+ white-space: nowrap;
83
+
84
+ b {
85
+ display: block;
86
+ color: ${GREEN_DARK};
87
+ font-weight: 600;
88
+ }
89
+ `;
90
+
91
+ const Label = styled.div`
92
+ font-size: 15px;
93
+ font-weight: 500;
94
+ color: ${GREEN_DARK};
95
+ margin: 8px 0 0;
96
+ letter-spacing: 0.2px;
97
+ `;
98
+
99
+ const VitalsStrip = styled.div`
100
+ display: flex;
101
+ align-items: center;
102
+ flex-wrap: wrap;
103
+ gap: 6px 16px;
104
+ margin-top: 18px;
105
+ padding: 11px 16px;
106
+ background: ${MINT};
107
+ border: 1px solid ${MINT_LINE};
108
+ border-radius: 6px;
109
+ `;
110
+
111
+ const VitalsLabel = styled.span`
112
+ font-family: 'IBM Plex Mono', monospace;
113
+ font-size: 10px;
114
+ font-weight: 600;
115
+ letter-spacing: 1.4px;
116
+ color: ${GREEN_DARK};
117
+ border-right: 1px solid ${MINT_LINE};
118
+ padding-right: 14px;
119
+ `;
120
+
121
+ const StyledContactInfo = styled(ContactInfo)`
122
+ display: flex;
123
+ flex-wrap: wrap;
124
+ justify-content: flex-start;
125
+ gap: 6px 22px;
126
+ font-family: 'IBM Plex Mono', monospace;
127
+ font-size: 12.5px;
128
+ color: ${BODY};
129
+
130
+ a {
131
+ color: ${BODY};
132
+ text-decoration: none;
133
+ }
134
+
135
+ a:hover {
136
+ color: ${GREEN_DARK};
137
+ text-decoration: underline;
138
+ }
139
+ `;
140
+
141
+ const ChartNote = styled.div`
142
+ margin-top: 22px;
143
+ padding: 16px 20px 16px 18px;
144
+ background: ${MINT};
145
+ border-left: 4px solid ${GREEN};
146
+ border-radius: 0 6px 6px 0;
147
+
148
+ span {
149
+ display: block;
150
+ font-family: 'IBM Plex Mono', monospace;
151
+ font-size: 10.5px;
152
+ letter-spacing: 1.4px;
153
+ text-transform: uppercase;
154
+ color: ${GREEN_DARK};
155
+ margin-bottom: 6px;
156
+ }
157
+
158
+ p {
159
+ margin: 0;
160
+ font-size: 15px;
161
+ line-height: 1.65;
162
+ color: ${INK};
163
+ }
164
+ `;
165
+
166
+ /* ---- sections ---- */
167
+ const StyledSection = styled(Section)`
168
+ margin-bottom: 34px;
169
+ `;
170
+
171
+ const TitleRow = styled.div`
172
+ display: flex;
173
+ align-items: center;
174
+ gap: 12px;
175
+ margin-bottom: 18px;
176
+ border-bottom: 1.5px solid ${GREEN};
177
+ padding-bottom: 8px;
178
+ `;
179
+
180
+ const SectionCode = styled.span`
181
+ font-family: 'IBM Plex Mono', monospace;
182
+ font-size: 11px;
183
+ font-weight: 600;
184
+ color: #ffffff;
185
+ background: ${GREEN};
186
+ padding: 2px 7px;
187
+ border-radius: 4px;
188
+ letter-spacing: 0.5px;
189
+ flex-shrink: 0;
190
+ `;
191
+
192
+ const StyledSectionTitle = styled(SectionTitle)`
193
+ font-size: 13px;
194
+ font-weight: 700;
195
+ text-transform: uppercase;
196
+ letter-spacing: 2px;
197
+ color: ${INK};
198
+ margin: 0;
199
+ padding-bottom: 0;
200
+ border-bottom: none;
201
+ `;
202
+
203
+ /* ---- chart rows ---- */
204
+ const ChartRow = styled.div`
205
+ display: grid;
206
+ grid-template-columns: 158px 1fr;
207
+ gap: 22px;
208
+ padding: 14px 0 16px;
209
+ border-bottom: 1px solid ${HAIR};
210
+
211
+ &:last-child {
212
+ border-bottom: none;
213
+ }
214
+
215
+ @media (max-width: 720px) {
216
+ grid-template-columns: 1fr;
217
+ gap: 8px;
218
+ }
219
+ `;
220
+
221
+ const VitalRail = styled.div`
222
+ border-left: 3px solid ${GREEN};
223
+ padding-left: 12px;
224
+ display: flex;
225
+ flex-direction: column;
226
+ gap: 5px;
227
+
228
+ @media (max-width: 720px) {
229
+ border-left: none;
230
+ padding-left: 0;
231
+ border-top: 2px solid ${MINT_LINE};
232
+ padding-top: 8px;
233
+ }
234
+ `;
235
+
236
+ const RailDate = styled.div`
237
+ font-family: 'IBM Plex Mono', monospace;
238
+ font-size: 12px;
239
+ font-weight: 500;
240
+ color: ${GREEN_DARK};
241
+ font-variant-numeric: tabular-nums;
242
+ `;
243
+
244
+ const RailMeta = styled.div`
245
+ font-family: 'IBM Plex Mono', monospace;
246
+ font-size: 11px;
247
+ text-transform: uppercase;
248
+ letter-spacing: 0.5px;
249
+ color: ${META};
250
+ `;
251
+
252
+ const Content = styled.div`
253
+ display: flex;
254
+ flex-direction: column;
255
+ gap: 4px;
256
+ `;
257
+
258
+ const ItemTitle = styled.h3`
259
+ font-size: 17px;
260
+ font-weight: 700;
261
+ margin: 0;
262
+ color: ${INK};
263
+
264
+ a {
265
+ color: ${INK};
266
+ text-decoration: none;
267
+ border-bottom: 1.5px solid ${MINT_LINE};
268
+ }
269
+ a:hover {
270
+ border-color: ${GREEN};
271
+ }
272
+ `;
273
+
274
+ const ItemSub = styled.div`
275
+ font-size: 14px;
276
+ font-weight: 500;
277
+ color: ${GREEN_DARK};
278
+ `;
279
+
280
+ const ItemDesc = styled.p`
281
+ margin: 6px 0 0;
282
+ font-size: 14px;
283
+ line-height: 1.6;
284
+ color: ${BODY};
285
+ `;
286
+
287
+ const Highlights = styled.ul`
288
+ margin: 8px 0 0;
289
+ padding: 0;
290
+ list-style: none;
291
+
292
+ li {
293
+ position: relative;
294
+ padding-left: 20px;
295
+ margin-bottom: 6px;
296
+ font-size: 14px;
297
+ line-height: 1.55;
298
+ color: ${BODY};
299
+
300
+ &::before {
301
+ content: '+';
302
+ position: absolute;
303
+ left: 2px;
304
+ top: -1px;
305
+ color: ${GREEN};
306
+ font-weight: 700;
307
+ font-family: 'IBM Plex Mono', monospace;
308
+ }
309
+ }
310
+ `;
311
+
312
+ /* ---- skills: lab-panel cards ---- */
313
+ const PanelGrid = styled.div`
314
+ display: grid;
315
+ grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
316
+ gap: 14px;
317
+ `;
318
+
319
+ const Panel = styled.div`
320
+ border: 1px solid ${MINT_LINE};
321
+ border-radius: 6px;
322
+ overflow: hidden;
323
+ background: #ffffff;
324
+ `;
325
+
326
+ const PanelHead = styled.div`
327
+ background: ${MINT};
328
+ border-bottom: 1px solid ${MINT_LINE};
329
+ padding: 8px 12px;
330
+ font-size: 12px;
331
+ font-weight: 700;
332
+ text-transform: uppercase;
333
+ letter-spacing: 1px;
334
+ color: ${GREEN_DARK};
335
+
336
+ small {
337
+ float: right;
338
+ font-family: 'IBM Plex Mono', monospace;
339
+ font-weight: 500;
340
+ letter-spacing: 0.3px;
341
+ text-transform: none;
342
+ color: ${META};
343
+ }
344
+ `;
345
+
346
+ const PanelBody = styled.div`
347
+ padding: 10px 12px 12px;
348
+ `;
349
+
350
+ const StyledBadgeList = styled(BadgeList)`
351
+ display: flex;
352
+ flex-wrap: wrap;
353
+ gap: 6px;
354
+ `;
355
+
356
+ const StyledBadge = styled(Badge)`
357
+ font-size: 12px;
358
+ padding: 2px 9px;
359
+ border-radius: 3px;
360
+ background: ${MINT};
361
+ border: 1px solid ${MINT_LINE};
362
+ color: ${BODY};
363
+ font-weight: 500;
364
+ `;
365
+
366
+ /* ---- simple records ---- */
367
+ const RecordList = styled.div`
368
+ display: flex;
369
+ flex-direction: column;
370
+ gap: 12px;
371
+ `;
372
+
373
+ const RecordItem = styled.div`
374
+ padding: 12px 16px;
375
+ border: 1px solid ${HAIR};
376
+ border-left: 3px solid ${GREEN};
377
+ border-radius: 0 6px 6px 0;
378
+
379
+ h4 {
380
+ margin: 0 0 3px;
381
+ font-size: 15px;
382
+ font-weight: 700;
383
+ color: ${INK};
384
+
385
+ a {
386
+ color: ${INK};
387
+ text-decoration: none;
388
+ border-bottom: 1.5px solid ${MINT_LINE};
389
+ }
390
+ a:hover {
391
+ border-color: ${GREEN};
392
+ }
393
+ }
394
+
395
+ .meta {
396
+ font-family: 'IBM Plex Mono', monospace;
397
+ font-size: 11.5px;
398
+ color: ${META};
399
+ margin: 0 0 4px;
400
+ }
401
+
402
+ p {
403
+ margin: 4px 0 0;
404
+ font-size: 14px;
405
+ color: ${BODY};
406
+ line-height: 1.55;
407
+ }
408
+ `;
409
+
410
+ const TwoCol = styled.div`
411
+ display: grid;
412
+ grid-template-columns: 1fr 1fr;
413
+ gap: 12px;
414
+
415
+ @media (max-width: 720px) {
416
+ grid-template-columns: 1fr;
417
+ }
418
+ `;
419
+
420
+ function recordCode(name) {
421
+ const initials = (name || 'Resume')
422
+ .split(/\s+/)
423
+ .map((w) => w[0])
424
+ .join('')
425
+ .toUpperCase()
426
+ .slice(0, 3);
427
+ let hash = 0;
428
+ for (let i = 0; i < (name || '').length; i += 1) {
429
+ hash = (hash * 31 + name.charCodeAt(i)) % 100000;
430
+ }
431
+ return `${initials}-${String(hash).padStart(5, '0')}`;
432
+ }
433
+
434
+ function Resume({ resume }) {
435
+ const {
436
+ basics = {},
437
+ work = [],
438
+ education = [],
439
+ skills = [],
440
+ projects = [],
441
+ volunteer = [],
442
+ awards = [],
443
+ certificates = [],
444
+ publications = [],
445
+ languages = [],
446
+ interests = [],
447
+ references = [],
448
+ } = resume;
449
+
450
+ let code = 0;
451
+ const nextCode = () => String((code += 1)).padStart(2, '0');
452
+
453
+ return (
454
+ <Layout>
455
+ <Header>
456
+ <ChartRule />
457
+ <ChartTop>
458
+ <div>{basics.name && <Name>{basics.name}</Name>}</div>
459
+ <RecordCode>
460
+ RECORD
461
+ <b>{recordCode(basics.name)}</b>
462
+ STATUS: ACTIVE
463
+ </RecordCode>
464
+ </ChartTop>
465
+ {basics.label && <Label>{basics.label}</Label>}
466
+ <VitalsStrip>
467
+ <VitalsLabel>VITALS</VitalsLabel>
468
+ <StyledContactInfo basics={basics} separator="·" />
469
+ </VitalsStrip>
470
+ {basics.summary && (
471
+ <ChartNote>
472
+ <span>Chart Note · Summary</span>
473
+ <p>{basics.summary}</p>
474
+ </ChartNote>
475
+ )}
476
+ </Header>
477
+
478
+ {work.length > 0 && (
479
+ <StyledSection>
480
+ <TitleRow>
481
+ <SectionCode>§{nextCode()}</SectionCode>
482
+ <StyledSectionTitle>
483
+ Clinical History · Experience
484
+ </StyledSectionTitle>
485
+ </TitleRow>
486
+ {work.map((job, i) => (
487
+ <ChartRow key={i}>
488
+ <VitalRail>
489
+ <RailDate>
490
+ <DateRange startDate={job.startDate} endDate={job.endDate} />
491
+ </RailDate>
492
+ {job.location && <RailMeta>{job.location}</RailMeta>}
493
+ </VitalRail>
494
+ <Content>
495
+ <ItemTitle>
496
+ {job.url ? (
497
+ <Link href={safeUrl(job.url)}>
498
+ {job.position || job.name}
499
+ </Link>
500
+ ) : (
501
+ job.position || job.name
502
+ )}
503
+ </ItemTitle>
504
+ {job.name && job.position && <ItemSub>{job.name}</ItemSub>}
505
+ {job.summary && <ItemDesc>{job.summary}</ItemDesc>}
506
+ {job.highlights?.length > 0 && (
507
+ <Highlights>
508
+ {job.highlights.map((h, j) => (
509
+ <li key={j}>{h}</li>
510
+ ))}
511
+ </Highlights>
512
+ )}
513
+ </Content>
514
+ </ChartRow>
515
+ ))}
516
+ </StyledSection>
517
+ )}
518
+
519
+ {education.length > 0 && (
520
+ <StyledSection>
521
+ <TitleRow>
522
+ <SectionCode>§{nextCode()}</SectionCode>
523
+ <StyledSectionTitle>Education</StyledSectionTitle>
524
+ </TitleRow>
525
+ {education.map((edu, i) => (
526
+ <ChartRow key={i}>
527
+ <VitalRail>
528
+ <RailDate>
529
+ <DateRange startDate={edu.startDate} endDate={edu.endDate} />
530
+ </RailDate>
531
+ {edu.score && <RailMeta>GPA {edu.score}</RailMeta>}
532
+ </VitalRail>
533
+ <Content>
534
+ <ItemTitle>{edu.institution}</ItemTitle>
535
+ {(edu.studyType || edu.area) && (
536
+ <ItemSub>
537
+ {[edu.studyType, edu.area].filter(Boolean).join(' · ')}
538
+ </ItemSub>
539
+ )}
540
+ {edu.courses?.length > 0 && (
541
+ <Highlights>
542
+ {edu.courses.map((c, j) => (
543
+ <li key={j}>{c}</li>
544
+ ))}
545
+ </Highlights>
546
+ )}
547
+ </Content>
548
+ </ChartRow>
549
+ ))}
550
+ </StyledSection>
551
+ )}
552
+
553
+ {skills.length > 0 && (
554
+ <StyledSection>
555
+ <TitleRow>
556
+ <SectionCode>§{nextCode()}</SectionCode>
557
+ <StyledSectionTitle>Diagnostic Panel · Skills</StyledSectionTitle>
558
+ </TitleRow>
559
+ <PanelGrid>
560
+ {skills.map((skill, i) => (
561
+ <Panel key={i}>
562
+ <PanelHead>
563
+ {skill.name}
564
+ {skill.level && <small>{skill.level}</small>}
565
+ </PanelHead>
566
+ <PanelBody>
567
+ {skill.keywords?.length > 0 && (
568
+ <StyledBadgeList>
569
+ {skill.keywords.map((k, j) => (
570
+ <StyledBadge key={j}>{k}</StyledBadge>
571
+ ))}
572
+ </StyledBadgeList>
573
+ )}
574
+ </PanelBody>
575
+ </Panel>
576
+ ))}
577
+ </PanelGrid>
578
+ </StyledSection>
579
+ )}
580
+
581
+ {projects.length > 0 && (
582
+ <StyledSection>
583
+ <TitleRow>
584
+ <SectionCode>§{nextCode()}</SectionCode>
585
+ <StyledSectionTitle>Procedures · Projects</StyledSectionTitle>
586
+ </TitleRow>
587
+ {projects.map((p, i) => (
588
+ <ChartRow key={i}>
589
+ <VitalRail>
590
+ <RailDate>
591
+ <DateRange startDate={p.startDate} endDate={p.endDate} />
592
+ </RailDate>
593
+ {p.type && <RailMeta>{p.type}</RailMeta>}
594
+ </VitalRail>
595
+ <Content>
596
+ <ItemTitle>
597
+ {p.url ? <Link href={safeUrl(p.url)}>{p.name}</Link> : p.name}
598
+ </ItemTitle>
599
+ {p.description && <ItemDesc>{p.description}</ItemDesc>}
600
+ {p.highlights?.length > 0 && (
601
+ <Highlights>
602
+ {p.highlights.map((h, j) => (
603
+ <li key={j}>{h}</li>
604
+ ))}
605
+ </Highlights>
606
+ )}
607
+ </Content>
608
+ </ChartRow>
609
+ ))}
610
+ </StyledSection>
611
+ )}
612
+
613
+ {volunteer.length > 0 && (
614
+ <StyledSection>
615
+ <TitleRow>
616
+ <SectionCode>§{nextCode()}</SectionCode>
617
+ <StyledSectionTitle>Community Care · Volunteer</StyledSectionTitle>
618
+ </TitleRow>
619
+ {volunteer.map((v, i) => (
620
+ <ChartRow key={i}>
621
+ <VitalRail>
622
+ <RailDate>
623
+ <DateRange startDate={v.startDate} endDate={v.endDate} />
624
+ </RailDate>
625
+ </VitalRail>
626
+ <Content>
627
+ <ItemTitle>{v.position}</ItemTitle>
628
+ {v.organization && <ItemSub>{v.organization}</ItemSub>}
629
+ {v.summary && <ItemDesc>{v.summary}</ItemDesc>}
630
+ {v.highlights?.length > 0 && (
631
+ <Highlights>
632
+ {v.highlights.map((h, j) => (
633
+ <li key={j}>{h}</li>
634
+ ))}
635
+ </Highlights>
636
+ )}
637
+ </Content>
638
+ </ChartRow>
639
+ ))}
640
+ </StyledSection>
641
+ )}
642
+
643
+ {awards.length > 0 && (
644
+ <StyledSection>
645
+ <TitleRow>
646
+ <SectionCode>§{nextCode()}</SectionCode>
647
+ <StyledSectionTitle>Awards</StyledSectionTitle>
648
+ </TitleRow>
649
+ <RecordList>
650
+ {awards.map((a, i) => (
651
+ <RecordItem key={i}>
652
+ <h4>{a.title}</h4>
653
+ <p className="meta">
654
+ {[a.awarder, a.date].filter(Boolean).join(' · ')}
655
+ </p>
656
+ {a.summary && <p>{a.summary}</p>}
657
+ </RecordItem>
658
+ ))}
659
+ </RecordList>
660
+ </StyledSection>
661
+ )}
662
+
663
+ {certificates.length > 0 && (
664
+ <StyledSection>
665
+ <TitleRow>
666
+ <SectionCode>§{nextCode()}</SectionCode>
667
+ <StyledSectionTitle>Certificates</StyledSectionTitle>
668
+ </TitleRow>
669
+ <RecordList>
670
+ {certificates.map((c, i) => (
671
+ <RecordItem key={i}>
672
+ <h4>
673
+ {c.url ? <Link href={safeUrl(c.url)}>{c.name}</Link> : c.name}
674
+ </h4>
675
+ <p className="meta">
676
+ {[c.issuer, c.date].filter(Boolean).join(' · ')}
677
+ </p>
678
+ </RecordItem>
679
+ ))}
680
+ </RecordList>
681
+ </StyledSection>
682
+ )}
683
+
684
+ {publications.length > 0 && (
685
+ <StyledSection>
686
+ <TitleRow>
687
+ <SectionCode>§{nextCode()}</SectionCode>
688
+ <StyledSectionTitle>Publications</StyledSectionTitle>
689
+ </TitleRow>
690
+ <RecordList>
691
+ {publications.map((pub, i) => (
692
+ <RecordItem key={i}>
693
+ <h4>
694
+ {pub.url ? (
695
+ <Link href={safeUrl(pub.url)}>{pub.name}</Link>
696
+ ) : (
697
+ pub.name
698
+ )}
699
+ </h4>
700
+ <p className="meta">
701
+ {[pub.publisher, pub.releaseDate].filter(Boolean).join(' · ')}
702
+ </p>
703
+ {pub.summary && <p>{pub.summary}</p>}
704
+ </RecordItem>
705
+ ))}
706
+ </RecordList>
707
+ </StyledSection>
708
+ )}
709
+
710
+ {languages.length > 0 && (
711
+ <StyledSection>
712
+ <TitleRow>
713
+ <SectionCode>§{nextCode()}</SectionCode>
714
+ <StyledSectionTitle>Languages</StyledSectionTitle>
715
+ </TitleRow>
716
+ <StyledBadgeList>
717
+ {languages.map((l, i) => (
718
+ <StyledBadge key={i}>
719
+ {l.language}
720
+ {l.fluency && ` — ${l.fluency}`}
721
+ </StyledBadge>
722
+ ))}
723
+ </StyledBadgeList>
724
+ </StyledSection>
725
+ )}
726
+
727
+ {interests.length > 0 && (
728
+ <StyledSection>
729
+ <TitleRow>
730
+ <SectionCode>§{nextCode()}</SectionCode>
731
+ <StyledSectionTitle>Interests</StyledSectionTitle>
732
+ </TitleRow>
733
+ <TwoCol>
734
+ {interests.map((it, i) => (
735
+ <RecordItem key={i}>
736
+ <h4>{it.name}</h4>
737
+ {it.keywords?.length > 0 && <p>{it.keywords.join(', ')}</p>}
738
+ </RecordItem>
739
+ ))}
740
+ </TwoCol>
741
+ </StyledSection>
742
+ )}
743
+
744
+ {references.length > 0 && (
745
+ <StyledSection>
746
+ <TitleRow>
747
+ <SectionCode>§{nextCode()}</SectionCode>
748
+ <StyledSectionTitle>References</StyledSectionTitle>
749
+ </TitleRow>
750
+ <RecordList>
751
+ {references.map((r, i) => (
752
+ <RecordItem key={i}>
753
+ <h4>{r.name}</h4>
754
+ {r.reference && <p>{r.reference}</p>}
755
+ </RecordItem>
756
+ ))}
757
+ </RecordList>
758
+ </StyledSection>
759
+ )}
760
+ </Layout>
761
+ );
762
+ }
763
+
764
+ export default Resume;