jsonresume-theme-new-york-editorial 0.1.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.
Files changed (3) hide show
  1. package/index.js +23 -0
  2. package/package.json +14 -0
  3. package/src/Resume.jsx +567 -0
package/index.js ADDED
@@ -0,0 +1,23 @@
1
+ import { renderToString } from 'react-dom/server';
2
+ import { ServerStyleSheet } from 'styled-components';
3
+ import Resume from './src/Resume.jsx';
4
+
5
+ export function render(resume) {
6
+ const sheet = new ServerStyleSheet();
7
+ const html = renderToString(sheet.collectStyles(<Resume resume={resume} />));
8
+ const styles = sheet.getStyleTags();
9
+ const title = (resume.basics && resume.basics.name) || 'Resume';
10
+
11
+ return `<!DOCTYPE html>
12
+ <html lang="en">
13
+ <head>
14
+ <meta charset="utf-8">
15
+ <title>${title}</title>
16
+ <meta name="viewport" content="width=device-width, initial-scale=1">
17
+ <link rel="preconnect" href="https://fonts.googleapis.com">
18
+ <link href="https://fonts.googleapis.com/css2?family=Merriweather:ital,wght@0,400;0,700;0,900;1,400&family=Source+Sans+Pro:wght@400;600&display=swap" rel="stylesheet">
19
+ ${styles}
20
+ </head>
21
+ <body>${html}</body>
22
+ </html>`;
23
+ }
package/package.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "jsonresume-theme-new-york-editorial",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "index.js",
6
+ "peerDependencies": {
7
+ "react": "^18.0.0 || ^19.0.0",
8
+ "react-dom": "^18.0.0 || ^19.0.0"
9
+ },
10
+ "dependencies": {
11
+ "styled-components": "^6.1.19",
12
+ "@resume/core": "0.1.0"
13
+ }
14
+ }
package/src/Resume.jsx ADDED
@@ -0,0 +1,567 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+ import {
4
+ Section,
5
+ SectionTitle,
6
+ DateRange,
7
+ ContactInfo,
8
+ Link,
9
+ } from '@resume/core';
10
+
11
+ const Layout = styled.div`
12
+ max-width: 680px;
13
+ margin: 0 auto;
14
+ padding: 80px 100px;
15
+ background: #ffffff;
16
+ font-family: 'Source Sans Pro', -apple-system, sans-serif;
17
+ color: #2a2a2a;
18
+ line-height: 1.75;
19
+
20
+ @media print {
21
+ padding: 60px 80px;
22
+ }
23
+
24
+ @media (max-width: 1024px) {
25
+ padding: 60px 50px;
26
+ }
27
+
28
+ @media (max-width: 640px) {
29
+ padding: 40px 24px;
30
+ max-width: 100%;
31
+ }
32
+ `;
33
+
34
+ const Header = styled.header`
35
+ margin-bottom: 60px;
36
+ padding-bottom: 40px;
37
+ border-bottom: 3px solid #222222;
38
+ text-align: center;
39
+ `;
40
+
41
+ const Name = styled.h1`
42
+ font-size: 52px;
43
+ font-weight: 900;
44
+ font-family: 'Merriweather', Georgia, serif;
45
+ color: #222222;
46
+ margin: 0 0 16px 0;
47
+ letter-spacing: -1px;
48
+ line-height: 1.1;
49
+ `;
50
+
51
+ const Label = styled.p`
52
+ font-size: 20px;
53
+ font-weight: 400;
54
+ font-family: 'Merriweather', Georgia, serif;
55
+ font-style: italic;
56
+ color: #555555;
57
+ margin: 0 0 28px 0;
58
+ letter-spacing: 0.3px;
59
+ `;
60
+
61
+ const StyledContactInfo = styled(ContactInfo)`
62
+ font-size: 15px;
63
+ color: #666666;
64
+ margin-bottom: 28px;
65
+ display: flex;
66
+ justify-content: center;
67
+ flex-wrap: wrap;
68
+ gap: 8px 20px;
69
+
70
+ a {
71
+ font-size: 15px;
72
+ color: #b22222;
73
+ text-decoration: none;
74
+ border-bottom: 1px solid transparent;
75
+ transition: border-color 0.2s;
76
+
77
+ &:hover {
78
+ border-bottom-color: #b22222;
79
+ }
80
+ }
81
+ `;
82
+
83
+ const Summary = styled.p`
84
+ font-size: 17px;
85
+ line-height: 1.8;
86
+ color: #3a3a3a;
87
+ margin: 28px 0 0 0;
88
+ text-align: left;
89
+ font-style: italic;
90
+ border-left: 3px solid #b22222;
91
+ padding-left: 20px;
92
+ `;
93
+
94
+ const StyledSection = styled(Section)`
95
+ margin-bottom: 56px;
96
+ `;
97
+
98
+ const StyledSectionTitle = styled(SectionTitle)`
99
+ font-size: 28px;
100
+ font-weight: 700;
101
+ font-family: 'Merriweather', Georgia, serif;
102
+ color: #222222;
103
+ margin: 0 0 32px 0;
104
+ padding-bottom: 12px;
105
+ border-bottom: 2px solid #e0e0e0;
106
+ position: relative;
107
+
108
+ &::after {
109
+ content: '';
110
+ position: absolute;
111
+ bottom: -2px;
112
+ left: 0;
113
+ width: 80px;
114
+ height: 2px;
115
+ background: #b22222;
116
+ }
117
+ `;
118
+
119
+ const WorkItem = styled.article`
120
+ margin-bottom: 44px;
121
+
122
+ &:last-child {
123
+ margin-bottom: 0;
124
+ }
125
+ `;
126
+
127
+ const WorkHeader = styled.div`
128
+ margin-bottom: 16px;
129
+ `;
130
+
131
+ const Position = styled.h3`
132
+ font-size: 22px;
133
+ font-weight: 700;
134
+ font-family: 'Merriweather', Georgia, serif;
135
+ color: #222222;
136
+ margin: 0 0 8px 0;
137
+ line-height: 1.3;
138
+ `;
139
+
140
+ const CompanyLine = styled.div`
141
+ font-size: 17px;
142
+ font-weight: 400;
143
+ color: #555555;
144
+ margin-bottom: 6px;
145
+ display: flex;
146
+ justify-content: space-between;
147
+ align-items: baseline;
148
+ flex-wrap: wrap;
149
+ gap: 8px;
150
+ `;
151
+
152
+ const Company = styled.span`
153
+ font-style: italic;
154
+ color: #444444;
155
+ `;
156
+
157
+ const StyledDateRange = styled(DateRange)`
158
+ font-size: 15px;
159
+ color: #777777;
160
+ font-variant-numeric: oldstyle-nums;
161
+ `;
162
+
163
+ const WorkSummary = styled.p`
164
+ margin: 16px 0;
165
+ color: #3a3a3a;
166
+ line-height: 1.8;
167
+ font-size: 16px;
168
+ `;
169
+
170
+ const HighlightsList = styled.ul`
171
+ margin: 16px 0 0 0;
172
+ padding-left: 28px;
173
+ list-style: none;
174
+
175
+ li {
176
+ position: relative;
177
+ margin-bottom: 12px;
178
+ padding-left: 0;
179
+ color: #3a3a3a;
180
+ line-height: 1.75;
181
+ font-size: 16px;
182
+
183
+ &::before {
184
+ content: '—';
185
+ position: absolute;
186
+ left: -28px;
187
+ color: #b22222;
188
+ font-weight: bold;
189
+ }
190
+ }
191
+ `;
192
+
193
+ const EducationItem = styled.article`
194
+ margin-bottom: 36px;
195
+
196
+ &:last-child {
197
+ margin-bottom: 0;
198
+ }
199
+ `;
200
+
201
+ const Degree = styled.h3`
202
+ font-size: 20px;
203
+ font-weight: 700;
204
+ font-family: 'Merriweather', Georgia, serif;
205
+ color: #222222;
206
+ margin: 0 0 8px 0;
207
+ `;
208
+
209
+ const InstitutionLine = styled.div`
210
+ font-size: 17px;
211
+ color: #555555;
212
+ margin-bottom: 6px;
213
+ display: flex;
214
+ justify-content: space-between;
215
+ align-items: baseline;
216
+ flex-wrap: wrap;
217
+ gap: 8px;
218
+ `;
219
+
220
+ const Institution = styled.span`
221
+ font-style: italic;
222
+ `;
223
+
224
+ const StudyType = styled.div`
225
+ font-size: 15px;
226
+ color: #777777;
227
+ margin-top: 6px;
228
+ `;
229
+
230
+ const SkillsContainer = styled.div`
231
+ display: flex;
232
+ flex-wrap: wrap;
233
+ gap: 32px;
234
+ `;
235
+
236
+ const SkillGroup = styled.div`
237
+ min-width: 200px;
238
+ flex: 1;
239
+ `;
240
+
241
+ const SkillName = styled.h4`
242
+ font-size: 17px;
243
+ font-weight: 700;
244
+ font-family: 'Merriweather', Georgia, serif;
245
+ color: #222222;
246
+ margin: 0 0 10px 0;
247
+ border-bottom: 1px solid #b22222;
248
+ padding-bottom: 6px;
249
+ display: inline-block;
250
+ `;
251
+
252
+ const KeywordList = styled.p`
253
+ font-size: 15px;
254
+ color: #555555;
255
+ line-height: 1.7;
256
+ margin: 0;
257
+ `;
258
+
259
+ const ProjectItem = styled.article`
260
+ margin-bottom: 40px;
261
+
262
+ &:last-child {
263
+ margin-bottom: 0;
264
+ }
265
+ `;
266
+
267
+ const ProjectName = styled.h3`
268
+ font-size: 20px;
269
+ font-weight: 700;
270
+ font-family: 'Merriweather', Georgia, serif;
271
+ color: #222222;
272
+ margin: 0 0 10px 0;
273
+ `;
274
+
275
+ const ProjectDescription = styled.p`
276
+ font-size: 16px;
277
+ color: #3a3a3a;
278
+ line-height: 1.75;
279
+ margin: 0 0 12px 0;
280
+ font-style: italic;
281
+ `;
282
+
283
+ const ProjectHighlights = styled.ul`
284
+ margin: 12px 0 0 0;
285
+ padding-left: 24px;
286
+ list-style: disc;
287
+
288
+ li {
289
+ margin-bottom: 8px;
290
+ color: #444444;
291
+ font-size: 15px;
292
+ line-height: 1.7;
293
+ }
294
+ `;
295
+
296
+ const SimpleList = styled.div`
297
+ display: flex;
298
+ flex-direction: column;
299
+ gap: 28px;
300
+ `;
301
+
302
+ const SimpleItem = styled.div``;
303
+
304
+ const ItemTitle = styled.h4`
305
+ font-size: 18px;
306
+ font-weight: 700;
307
+ font-family: 'Merriweather', Georgia, serif;
308
+ color: #222222;
309
+ margin: 0 0 8px 0;
310
+ `;
311
+
312
+ const ItemMeta = styled.div`
313
+ font-size: 15px;
314
+ color: #777777;
315
+ margin-bottom: 8px;
316
+ font-style: italic;
317
+ `;
318
+
319
+ const ItemDescription = styled.p`
320
+ font-size: 15px;
321
+ color: #444444;
322
+ margin: 0;
323
+ line-height: 1.7;
324
+ `;
325
+
326
+ const Divider = styled.hr`
327
+ border: none;
328
+ border-top: 1px solid #e0e0e0;
329
+ margin: 48px 0;
330
+ `;
331
+
332
+ function Resume({ resume }) {
333
+ const {
334
+ basics = {},
335
+ work = [],
336
+ education = [],
337
+ skills = [],
338
+ projects = [],
339
+ volunteer = [],
340
+ awards = [],
341
+ publications = [],
342
+ languages = [],
343
+ interests = [],
344
+ references = [],
345
+ } = resume;
346
+
347
+ return (
348
+ <Layout>
349
+ <Header>
350
+ <Name>{basics.name}</Name>
351
+ {basics.label && <Label>{basics.label}</Label>}
352
+ <StyledContactInfo basics={basics} />
353
+ {basics.summary && <Summary>{basics.summary}</Summary>}
354
+ </Header>
355
+
356
+ {work && work.length > 0 && (
357
+ <StyledSection>
358
+ <StyledSectionTitle>Experience</StyledSectionTitle>
359
+ {work.map((job, index) => (
360
+ <WorkItem key={index}>
361
+ <WorkHeader>
362
+ <Position>{job.position}</Position>
363
+ <CompanyLine>
364
+ <Company>{job.name}</Company>
365
+ <StyledDateRange
366
+ startDate={job.startDate}
367
+ endDate={job.endDate}
368
+ />
369
+ </CompanyLine>
370
+ </WorkHeader>
371
+ {job.summary && <WorkSummary>{job.summary}</WorkSummary>}
372
+ {job.highlights && job.highlights.length > 0 && (
373
+ <HighlightsList>
374
+ {job.highlights.map((highlight, i) => (
375
+ <li
376
+ key={i}
377
+ dangerouslySetInnerHTML={{ __html: highlight }}
378
+ />
379
+ ))}
380
+ </HighlightsList>
381
+ )}
382
+ </WorkItem>
383
+ ))}
384
+ </StyledSection>
385
+ )}
386
+
387
+ {skills && skills.length > 0 && (
388
+ <StyledSection>
389
+ <StyledSectionTitle>Expertise</StyledSectionTitle>
390
+ <SkillsContainer>
391
+ {skills.map((skill, index) => (
392
+ <SkillGroup key={index}>
393
+ <SkillName>{skill.name}</SkillName>
394
+ {skill.keywords && skill.keywords.length > 0 && (
395
+ <KeywordList>{skill.keywords.join(', ')}</KeywordList>
396
+ )}
397
+ </SkillGroup>
398
+ ))}
399
+ </SkillsContainer>
400
+ </StyledSection>
401
+ )}
402
+
403
+ {education && education.length > 0 && (
404
+ <StyledSection>
405
+ <StyledSectionTitle>Education</StyledSectionTitle>
406
+ {education.map((edu, index) => (
407
+ <EducationItem key={index}>
408
+ <Degree>{edu.area}</Degree>
409
+ <InstitutionLine>
410
+ <Institution>{edu.institution}</Institution>
411
+ <StyledDateRange
412
+ startDate={edu.startDate}
413
+ endDate={edu.endDate}
414
+ />
415
+ </InstitutionLine>
416
+ {edu.studyType && <StudyType>{edu.studyType}</StudyType>}
417
+ {edu.score && <ItemMeta>GPA: {edu.score}</ItemMeta>}
418
+ </EducationItem>
419
+ ))}
420
+ </StyledSection>
421
+ )}
422
+
423
+ {projects && projects.length > 0 && (
424
+ <StyledSection>
425
+ <StyledSectionTitle>Projects</StyledSectionTitle>
426
+ {projects.map((project, index) => (
427
+ <ProjectItem key={index}>
428
+ <ProjectName>
429
+ {project.url ? (
430
+ <Link href={project.url}>{project.name}</Link>
431
+ ) : (
432
+ project.name
433
+ )}
434
+ </ProjectName>
435
+ {project.description && (
436
+ <ProjectDescription>{project.description}</ProjectDescription>
437
+ )}
438
+ {project.highlights && project.highlights.length > 0 && (
439
+ <ProjectHighlights>
440
+ {project.highlights.map((highlight, i) => (
441
+ <li key={i}>{highlight}</li>
442
+ ))}
443
+ </ProjectHighlights>
444
+ )}
445
+ </ProjectItem>
446
+ ))}
447
+ </StyledSection>
448
+ )}
449
+
450
+ {publications && publications.length > 0 && (
451
+ <StyledSection>
452
+ <StyledSectionTitle>Publications</StyledSectionTitle>
453
+ {publications.map((pub, index) => (
454
+ <ProjectItem key={index}>
455
+ <ProjectName>
456
+ {pub.url ? <Link href={pub.url}>{pub.name}</Link> : pub.name}
457
+ </ProjectName>
458
+ <ItemMeta>
459
+ {pub.publisher}
460
+ {pub.releaseDate && <> • {pub.releaseDate}</>}
461
+ </ItemMeta>
462
+ {pub.summary && (
463
+ <ProjectDescription>{pub.summary}</ProjectDescription>
464
+ )}
465
+ </ProjectItem>
466
+ ))}
467
+ </StyledSection>
468
+ )}
469
+
470
+ {volunteer && volunteer.length > 0 && (
471
+ <StyledSection>
472
+ <StyledSectionTitle>Volunteer Work</StyledSectionTitle>
473
+ <SimpleList>
474
+ {volunteer.map((vol, index) => (
475
+ <SimpleItem key={index}>
476
+ <ItemTitle>{vol.position}</ItemTitle>
477
+ <ItemMeta>
478
+ {vol.organization}
479
+ {vol.startDate && (
480
+ <>
481
+ {' • '}
482
+ <DateRange
483
+ startDate={vol.startDate}
484
+ endDate={vol.endDate}
485
+ />
486
+ </>
487
+ )}
488
+ </ItemMeta>
489
+ {vol.summary && (
490
+ <ItemDescription>{vol.summary}</ItemDescription>
491
+ )}
492
+ </SimpleItem>
493
+ ))}
494
+ </SimpleList>
495
+ </StyledSection>
496
+ )}
497
+
498
+ {awards && awards.length > 0 && (
499
+ <StyledSection>
500
+ <StyledSectionTitle>Awards & Honors</StyledSectionTitle>
501
+ <SimpleList>
502
+ {awards.map((award, index) => (
503
+ <SimpleItem key={index}>
504
+ <ItemTitle>{award.title}</ItemTitle>
505
+ <ItemMeta>
506
+ {award.awarder}
507
+ {award.date && <> • {award.date}</>}
508
+ </ItemMeta>
509
+ {award.summary && (
510
+ <ItemDescription>{award.summary}</ItemDescription>
511
+ )}
512
+ </SimpleItem>
513
+ ))}
514
+ </SimpleList>
515
+ </StyledSection>
516
+ )}
517
+
518
+ {languages && languages.length > 0 && (
519
+ <StyledSection>
520
+ <StyledSectionTitle>Languages</StyledSectionTitle>
521
+ <SkillsContainer>
522
+ {languages.map((lang, index) => (
523
+ <SkillGroup key={index}>
524
+ <SkillName>{lang.language}</SkillName>
525
+ {lang.fluency && <KeywordList>{lang.fluency}</KeywordList>}
526
+ </SkillGroup>
527
+ ))}
528
+ </SkillsContainer>
529
+ </StyledSection>
530
+ )}
531
+
532
+ {interests && interests.length > 0 && (
533
+ <StyledSection>
534
+ <StyledSectionTitle>Interests</StyledSectionTitle>
535
+ <SkillsContainer>
536
+ {interests.map((interest, index) => (
537
+ <SkillGroup key={index}>
538
+ <SkillName>{interest.name}</SkillName>
539
+ {interest.keywords && interest.keywords.length > 0 && (
540
+ <KeywordList>{interest.keywords.join(', ')}</KeywordList>
541
+ )}
542
+ </SkillGroup>
543
+ ))}
544
+ </SkillsContainer>
545
+ </StyledSection>
546
+ )}
547
+
548
+ {references && references.length > 0 && (
549
+ <StyledSection>
550
+ <StyledSectionTitle>References</StyledSectionTitle>
551
+ <SimpleList>
552
+ {references.map((ref, index) => (
553
+ <SimpleItem key={index}>
554
+ <ItemTitle>{ref.name}</ItemTitle>
555
+ {ref.reference && (
556
+ <ItemDescription>{ref.reference}</ItemDescription>
557
+ )}
558
+ </SimpleItem>
559
+ ))}
560
+ </SimpleList>
561
+ </StyledSection>
562
+ )}
563
+ </Layout>
564
+ );
565
+ }
566
+
567
+ export default Resume;