jsonresume-theme-californian-warm 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 +510 -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=Nunito:wght@400;600;700;800&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-californian-warm",
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,510 @@
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 '@resume/core';
13
+
14
+ const Layout = styled.div`
15
+ max-width: 820px;
16
+ margin: 0 auto;
17
+ padding: 60px 50px;
18
+ background: #fff8f1;
19
+ font-family: 'Nunito', -apple-system, BlinkMacSystemFont, sans-serif;
20
+ color: #3d2a1f;
21
+ line-height: 1.8;
22
+ font-size: 15px;
23
+
24
+ @media print {
25
+ background: white;
26
+ padding: 40px 30px;
27
+ }
28
+ `;
29
+
30
+ const Header = styled.header`
31
+ margin-bottom: 50px;
32
+ padding: 40px;
33
+ background: linear-gradient(135deg, #fef5e7 0%, #fef0dc 100%);
34
+ border-radius: 20px;
35
+ box-shadow: 0 4px 20px rgba(245, 158, 11, 0.08);
36
+ `;
37
+
38
+ const Name = styled.h1`
39
+ font-size: 48px;
40
+ font-weight: 800;
41
+ margin: 0 0 12px 0;
42
+ color: #d97706;
43
+ letter-spacing: -0.5px;
44
+ line-height: 1.2;
45
+ `;
46
+
47
+ const Tagline = styled.div`
48
+ font-size: 20px;
49
+ color: #92400e;
50
+ margin: 0 0 24px 0;
51
+ font-weight: 600;
52
+ opacity: 0.9;
53
+ `;
54
+
55
+ const Summary = styled.p`
56
+ font-size: 16px;
57
+ line-height: 1.8;
58
+ color: #4d3319;
59
+ margin: 24px 0 30px 0;
60
+ padding: 20px;
61
+ background: rgba(255, 255, 255, 0.7);
62
+ border-radius: 12px;
63
+ border-left: 4px solid #f59e0b;
64
+ `;
65
+
66
+ const StyledContactInfo = styled(ContactInfo)`
67
+ display: flex;
68
+ flex-wrap: wrap;
69
+ gap: 20px;
70
+ margin-top: 20px;
71
+
72
+ a {
73
+ color: #d97706;
74
+ text-decoration: none;
75
+ font-weight: 600;
76
+ font-size: 14px;
77
+ transition: all 0.2s ease;
78
+ padding: 8px 16px;
79
+ background: rgba(251, 191, 36, 0.15);
80
+ border-radius: 8px;
81
+
82
+ &:hover {
83
+ background: rgba(251, 191, 36, 0.25);
84
+ transform: translateY(-1px);
85
+ }
86
+ }
87
+ `;
88
+
89
+ const StyledSection = styled(Section)`
90
+ margin-bottom: 50px;
91
+ `;
92
+
93
+ const StyledSectionTitle = styled(SectionTitle)`
94
+ font-size: 28px;
95
+ font-weight: 700;
96
+ color: #ea580c;
97
+ margin: 0 0 30px 0;
98
+ padding-bottom: 12px;
99
+ border-bottom: 3px solid #fed7aa;
100
+ letter-spacing: -0.3px;
101
+ `;
102
+
103
+ const WorkItem = styled.div`
104
+ margin-bottom: 40px;
105
+ padding: 30px;
106
+ background: white;
107
+ border-radius: 16px;
108
+ box-shadow: 0 2px 12px rgba(217, 119, 6, 0.08);
109
+ transition: all 0.3s ease;
110
+
111
+ &:hover {
112
+ box-shadow: 0 4px 20px rgba(217, 119, 6, 0.12);
113
+ transform: translateY(-2px);
114
+ }
115
+
116
+ &:last-child {
117
+ margin-bottom: 0;
118
+ }
119
+ `;
120
+
121
+ const ItemHeader = styled.div`
122
+ display: flex;
123
+ justify-content: space-between;
124
+ align-items: flex-start;
125
+ margin-bottom: 16px;
126
+ flex-wrap: wrap;
127
+ gap: 12px;
128
+ `;
129
+
130
+ const ItemTitle = styled.h3`
131
+ font-size: 22px;
132
+ font-weight: 700;
133
+ margin: 0;
134
+ color: #d97706;
135
+ flex: 1;
136
+ min-width: 200px;
137
+ `;
138
+
139
+ const ItemDate = styled.div`
140
+ font-size: 14px;
141
+ font-weight: 600;
142
+ color: #92400e;
143
+ opacity: 0.8;
144
+ background: #fef3c7;
145
+ padding: 6px 14px;
146
+ border-radius: 20px;
147
+ white-space: nowrap;
148
+ `;
149
+
150
+ const ItemSubtitle = styled.div`
151
+ font-size: 18px;
152
+ font-weight: 600;
153
+ color: #78350f;
154
+ margin-bottom: 8px;
155
+ `;
156
+
157
+ const ItemLocation = styled.div`
158
+ font-size: 14px;
159
+ color: #a16207;
160
+ font-weight: 600;
161
+ margin-bottom: 12px;
162
+ opacity: 0.9;
163
+ `;
164
+
165
+ const ItemDescription = styled.p`
166
+ font-size: 15px;
167
+ line-height: 1.8;
168
+ color: #4d3319;
169
+ margin: 16px 0;
170
+ `;
171
+
172
+ const HighlightsList = styled.ul`
173
+ margin: 16px 0 0 0;
174
+ padding-left: 28px;
175
+ list-style: none;
176
+
177
+ li {
178
+ position: relative;
179
+ margin-bottom: 12px;
180
+ font-size: 15px;
181
+ line-height: 1.7;
182
+ color: #4d3319;
183
+
184
+ &::before {
185
+ content: '✦';
186
+ position: absolute;
187
+ left: -28px;
188
+ color: #f59e0b;
189
+ font-size: 14px;
190
+ }
191
+ }
192
+ `;
193
+
194
+ const SkillsContainer = styled.div`
195
+ display: flex;
196
+ flex-direction: column;
197
+ gap: 30px;
198
+ `;
199
+
200
+ const SkillCategory = styled.div`
201
+ padding: 28px;
202
+ background: white;
203
+ border-radius: 16px;
204
+ box-shadow: 0 2px 12px rgba(217, 119, 6, 0.08);
205
+
206
+ h4 {
207
+ font-size: 18px;
208
+ font-weight: 700;
209
+ color: #ea580c;
210
+ margin: 0 0 18px 0;
211
+ text-transform: none;
212
+ }
213
+ `;
214
+
215
+ const StyledBadgeList = styled(BadgeList)`
216
+ display: flex;
217
+ flex-wrap: wrap;
218
+ gap: 10px;
219
+ `;
220
+
221
+ const StyledBadge = styled(Badge)`
222
+ font-size: 14px;
223
+ padding: 10px 18px;
224
+ background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
225
+ border: none;
226
+ color: #92400e;
227
+ font-weight: 600;
228
+ border-radius: 12px;
229
+ transition: all 0.2s ease;
230
+
231
+ &:hover {
232
+ transform: scale(1.05);
233
+ box-shadow: 0 2px 8px rgba(245, 158, 11, 0.2);
234
+ }
235
+ `;
236
+
237
+ const SimpleCard = styled.div`
238
+ padding: 24px;
239
+ background: white;
240
+ border-radius: 14px;
241
+ box-shadow: 0 2px 10px rgba(217, 119, 6, 0.06);
242
+ margin-bottom: 20px;
243
+
244
+ h4 {
245
+ font-size: 18px;
246
+ font-weight: 700;
247
+ color: #d97706;
248
+ margin: 0 0 10px 0;
249
+ }
250
+
251
+ p {
252
+ font-size: 14px;
253
+ margin: 6px 0 0 0;
254
+ color: #78350f;
255
+ }
256
+
257
+ &:last-child {
258
+ margin-bottom: 0;
259
+ }
260
+ `;
261
+
262
+ const EducationItem = styled(WorkItem)``;
263
+
264
+ const ProjectItem = styled(WorkItem)``;
265
+
266
+ function Resume({ resume }) {
267
+ const {
268
+ basics = {},
269
+ work = [],
270
+ education = [],
271
+ skills = [],
272
+ projects = [],
273
+ volunteer = [],
274
+ awards = [],
275
+ publications = [],
276
+ languages = [],
277
+ interests = [],
278
+ references = [],
279
+ } = resume;
280
+
281
+ return (
282
+ <Layout>
283
+ <Header>
284
+ {basics.name && <Name>{basics.name}</Name>}
285
+ {basics.label && <Tagline>{basics.label}</Tagline>}
286
+ {basics.summary && <Summary>{basics.summary}</Summary>}
287
+ <StyledContactInfo
288
+ email={basics.email}
289
+ phone={basics.phone}
290
+ url={basics.url}
291
+ location={basics.location}
292
+ profiles={basics.profiles}
293
+ />
294
+ </Header>
295
+
296
+ {work.length > 0 && (
297
+ <StyledSection>
298
+ <StyledSectionTitle>Experience</StyledSectionTitle>
299
+ {work.map((job, index) => (
300
+ <WorkItem key={index}>
301
+ <ItemHeader>
302
+ <ItemTitle>{job.position || job.name}</ItemTitle>
303
+ <ItemDate>
304
+ <DateRange startDate={job.startDate} endDate={job.endDate} />
305
+ </ItemDate>
306
+ </ItemHeader>
307
+ {job.name && <ItemSubtitle>{job.name}</ItemSubtitle>}
308
+ {job.location && <ItemLocation>{job.location}</ItemLocation>}
309
+ {job.summary && <ItemDescription>{job.summary}</ItemDescription>}
310
+ {job.highlights && job.highlights.length > 0 && (
311
+ <HighlightsList>
312
+ {job.highlights.map((highlight, i) => (
313
+ <li key={i}>{highlight}</li>
314
+ ))}
315
+ </HighlightsList>
316
+ )}
317
+ </WorkItem>
318
+ ))}
319
+ </StyledSection>
320
+ )}
321
+
322
+ {education.length > 0 && (
323
+ <StyledSection>
324
+ <StyledSectionTitle>Education</StyledSectionTitle>
325
+ {education.map((edu, index) => (
326
+ <EducationItem key={index}>
327
+ <ItemHeader>
328
+ <ItemTitle>{edu.institution}</ItemTitle>
329
+ <ItemDate>
330
+ <DateRange startDate={edu.startDate} endDate={edu.endDate} />
331
+ </ItemDate>
332
+ </ItemHeader>
333
+ {edu.studyType && edu.area && (
334
+ <ItemSubtitle>
335
+ {edu.studyType} in {edu.area}
336
+ </ItemSubtitle>
337
+ )}
338
+ {edu.score && <ItemDescription>GPA: {edu.score}</ItemDescription>}
339
+ {edu.courses && edu.courses.length > 0 && (
340
+ <HighlightsList>
341
+ {edu.courses.map((course, i) => (
342
+ <li key={i}>{course}</li>
343
+ ))}
344
+ </HighlightsList>
345
+ )}
346
+ </EducationItem>
347
+ ))}
348
+ </StyledSection>
349
+ )}
350
+
351
+ {skills.length > 0 && (
352
+ <StyledSection>
353
+ <StyledSectionTitle>Skills</StyledSectionTitle>
354
+ <SkillsContainer>
355
+ {skills.map((skill, index) => (
356
+ <SkillCategory key={index}>
357
+ <h4>{skill.name}</h4>
358
+ <StyledBadgeList>
359
+ {skill.keywords?.map((keyword, i) => (
360
+ <StyledBadge key={i}>{keyword}</StyledBadge>
361
+ ))}
362
+ </StyledBadgeList>
363
+ </SkillCategory>
364
+ ))}
365
+ </SkillsContainer>
366
+ </StyledSection>
367
+ )}
368
+
369
+ {projects.length > 0 && (
370
+ <StyledSection>
371
+ <StyledSectionTitle>Projects</StyledSectionTitle>
372
+ {projects.map((project, index) => (
373
+ <ProjectItem key={index}>
374
+ <ItemHeader>
375
+ <ItemTitle>
376
+ {project.url ? (
377
+ <Link href={safeUrl(project.url)}>{project.name}</Link>
378
+ ) : (
379
+ project.name
380
+ )}
381
+ </ItemTitle>
382
+ <ItemDate>
383
+ <DateRange
384
+ startDate={project.startDate}
385
+ endDate={project.endDate}
386
+ />
387
+ </ItemDate>
388
+ </ItemHeader>
389
+ {project.type && <ItemLocation>{project.type}</ItemLocation>}
390
+ {project.description && (
391
+ <ItemDescription>{project.description}</ItemDescription>
392
+ )}
393
+ {project.highlights && project.highlights.length > 0 && (
394
+ <HighlightsList>
395
+ {project.highlights.map((highlight, i) => (
396
+ <li key={i}>{highlight}</li>
397
+ ))}
398
+ </HighlightsList>
399
+ )}
400
+ </ProjectItem>
401
+ ))}
402
+ </StyledSection>
403
+ )}
404
+
405
+ {awards.length > 0 && (
406
+ <StyledSection>
407
+ <StyledSectionTitle>Awards</StyledSectionTitle>
408
+ {awards.map((award, index) => (
409
+ <SimpleCard key={index}>
410
+ <h4>{award.title}</h4>
411
+ <p>
412
+ {award.awarder} {award.date && `• ${award.date}`}
413
+ </p>
414
+ {award.summary && <p>{award.summary}</p>}
415
+ </SimpleCard>
416
+ ))}
417
+ </StyledSection>
418
+ )}
419
+
420
+ {publications.length > 0 && (
421
+ <StyledSection>
422
+ <StyledSectionTitle>Publications</StyledSectionTitle>
423
+ {publications.map((pub, index) => (
424
+ <SimpleCard key={index}>
425
+ <h4>
426
+ {pub.url ? (
427
+ <Link href={safeUrl(pub.url)}>{pub.name}</Link>
428
+ ) : (
429
+ pub.name
430
+ )}
431
+ </h4>
432
+ <p>
433
+ {pub.publisher} {pub.releaseDate && `• ${pub.releaseDate}`}
434
+ </p>
435
+ {pub.summary && <p>{pub.summary}</p>}
436
+ </SimpleCard>
437
+ ))}
438
+ </StyledSection>
439
+ )}
440
+
441
+ {volunteer.length > 0 && (
442
+ <StyledSection>
443
+ <StyledSectionTitle>Volunteer</StyledSectionTitle>
444
+ {volunteer.map((vol, index) => (
445
+ <WorkItem key={index}>
446
+ <ItemHeader>
447
+ <ItemTitle>{vol.position}</ItemTitle>
448
+ <ItemDate>
449
+ <DateRange startDate={vol.startDate} endDate={vol.endDate} />
450
+ </ItemDate>
451
+ </ItemHeader>
452
+ {vol.organization && (
453
+ <ItemSubtitle>{vol.organization}</ItemSubtitle>
454
+ )}
455
+ {vol.summary && <ItemDescription>{vol.summary}</ItemDescription>}
456
+ {vol.highlights && vol.highlights.length > 0 && (
457
+ <HighlightsList>
458
+ {vol.highlights.map((highlight, i) => (
459
+ <li key={i}>{highlight}</li>
460
+ ))}
461
+ </HighlightsList>
462
+ )}
463
+ </WorkItem>
464
+ ))}
465
+ </StyledSection>
466
+ )}
467
+
468
+ {languages.length > 0 && (
469
+ <StyledSection>
470
+ <StyledSectionTitle>Languages</StyledSectionTitle>
471
+ <StyledBadgeList>
472
+ {languages.map((lang, index) => (
473
+ <StyledBadge key={index}>
474
+ {lang.language} {lang.fluency && `— ${lang.fluency}`}
475
+ </StyledBadge>
476
+ ))}
477
+ </StyledBadgeList>
478
+ </StyledSection>
479
+ )}
480
+
481
+ {interests.length > 0 && (
482
+ <StyledSection>
483
+ <StyledSectionTitle>Interests</StyledSectionTitle>
484
+ {interests.map((interest, index) => (
485
+ <SimpleCard key={index}>
486
+ <h4>{interest.name}</h4>
487
+ {interest.keywords && interest.keywords.length > 0 && (
488
+ <p>{interest.keywords.join(', ')}</p>
489
+ )}
490
+ </SimpleCard>
491
+ ))}
492
+ </StyledSection>
493
+ )}
494
+
495
+ {references.length > 0 && (
496
+ <StyledSection>
497
+ <StyledSectionTitle>References</StyledSectionTitle>
498
+ {references.map((ref, index) => (
499
+ <SimpleCard key={index}>
500
+ <h4>{ref.name}</h4>
501
+ {ref.reference && <p>{ref.reference}</p>}
502
+ </SimpleCard>
503
+ ))}
504
+ </StyledSection>
505
+ )}
506
+ </Layout>
507
+ );
508
+ }
509
+
510
+ export default Resume;