jsonresume-theme-government-standard 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.
- package/README.md +57 -0
- package/package.json +24 -0
- package/src/Resume.jsx +294 -0
- package/src/components/EducationSection.jsx +33 -0
- package/src/components/OtherSections.jsx +168 -0
- package/src/components/SkillsSection.jsx +26 -0
- package/src/components/WorkSection.jsx +43 -0
- package/src/index.js +51 -0
- package/src/styles.js +212 -0
package/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Government Standard Theme
|
|
2
|
+
|
|
3
|
+
A formal, conservative JSON Resume theme designed for government, compliance, and defense sector roles.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Ultra-Traditional Layout**: Single column with clear section separations
|
|
8
|
+
- **Formal Typography**: Times New Roman or Georgia serif fonts, 12pt body text
|
|
9
|
+
- **Maximum Compliance**: Grayscale only (black, dark gray, white)
|
|
10
|
+
- **ATS-Optimized**: No color dependencies, clean structure
|
|
11
|
+
- **Print-Ready**: Proper margins and page breaks for physical documents
|
|
12
|
+
|
|
13
|
+
## Design Philosophy
|
|
14
|
+
|
|
15
|
+
This theme prioritizes clarity and compliance over aesthetics, making it ideal for:
|
|
16
|
+
|
|
17
|
+
- Government positions
|
|
18
|
+
- Defense contractors
|
|
19
|
+
- Civil service roles
|
|
20
|
+
- Compliance-focused industries
|
|
21
|
+
- Organizations with strict document formatting requirements
|
|
22
|
+
|
|
23
|
+
## Color Palette
|
|
24
|
+
|
|
25
|
+
- **Text**: #000000 (pure black)
|
|
26
|
+
- **Secondary Text**: #111827 (dark gray)
|
|
27
|
+
- **Background**: #ffffff (white)
|
|
28
|
+
- **Borders**: #000000 (black)
|
|
29
|
+
|
|
30
|
+
No accent colors are used to maintain maximum professionalism and ATS compatibility.
|
|
31
|
+
|
|
32
|
+
## Typography
|
|
33
|
+
|
|
34
|
+
- **Font Family**: Times New Roman, Georgia (serif)
|
|
35
|
+
- **Body Text**: 12pt
|
|
36
|
+
- **Headings**: 13-18pt bold
|
|
37
|
+
- **Section Titles**: 14pt bold uppercase
|
|
38
|
+
|
|
39
|
+
## Supported Sections
|
|
40
|
+
|
|
41
|
+
All 12 JSON Resume sections:
|
|
42
|
+
|
|
43
|
+
1. Professional Summary
|
|
44
|
+
2. Professional Experience
|
|
45
|
+
3. Education
|
|
46
|
+
4. Professional Skills
|
|
47
|
+
5. Projects
|
|
48
|
+
6. Volunteer Experience
|
|
49
|
+
7. Awards and Honors
|
|
50
|
+
8. Publications
|
|
51
|
+
9. Languages
|
|
52
|
+
10. Professional Interests
|
|
53
|
+
11. References
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
This theme is automatically available in the JSON Resume registry theme selector.
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jsonresume-theme-government-standard",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Government/compliance roles - conservative, by-the-book formatting",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"jsonresume",
|
|
10
|
+
"theme",
|
|
11
|
+
"government",
|
|
12
|
+
"formal",
|
|
13
|
+
"compliance",
|
|
14
|
+
"ats"
|
|
15
|
+
],
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
18
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"styled-components": "^6.1.19",
|
|
22
|
+
"@resume/core": "0.1.0"
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/Resume.jsx
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import { Section, SectionTitle, ContactInfo } from '@resume/core';
|
|
4
|
+
import { WorkSection } from './components/WorkSection.jsx';
|
|
5
|
+
import { EducationSection } from './components/EducationSection.jsx';
|
|
6
|
+
import { SkillsSection } from './components/SkillsSection.jsx';
|
|
7
|
+
import {
|
|
8
|
+
ProjectsSection,
|
|
9
|
+
VolunteerSection,
|
|
10
|
+
AwardsSection,
|
|
11
|
+
PublicationsSection,
|
|
12
|
+
LanguagesSection,
|
|
13
|
+
InterestsSection,
|
|
14
|
+
ReferencesSection,
|
|
15
|
+
} from './components/OtherSections.jsx';
|
|
16
|
+
|
|
17
|
+
// Styled components moved inline to fix webpack resolution
|
|
18
|
+
const Layout = styled.div`
|
|
19
|
+
max-width: 8.5in;
|
|
20
|
+
margin: 0 auto;
|
|
21
|
+
padding: 1in;
|
|
22
|
+
background: #ffffff;
|
|
23
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
24
|
+
font-size: 12pt;
|
|
25
|
+
color: #000000;
|
|
26
|
+
line-height: 1.4;
|
|
27
|
+
|
|
28
|
+
@media print {
|
|
29
|
+
padding: 0;
|
|
30
|
+
margin: 0;
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
const Header = styled.header`
|
|
35
|
+
text-align: center;
|
|
36
|
+
margin-bottom: 24pt;
|
|
37
|
+
padding-bottom: 12pt;
|
|
38
|
+
border-bottom: 2pt solid #000000;
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
const Name = styled.h1`
|
|
42
|
+
font-size: 18pt;
|
|
43
|
+
font-weight: bold;
|
|
44
|
+
color: #000000;
|
|
45
|
+
margin: 0 0 6pt 0;
|
|
46
|
+
letter-spacing: 0;
|
|
47
|
+
text-transform: uppercase;
|
|
48
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
49
|
+
`;
|
|
50
|
+
|
|
51
|
+
const Label = styled.div`
|
|
52
|
+
font-size: 12pt;
|
|
53
|
+
color: #000000;
|
|
54
|
+
margin-bottom: 8pt;
|
|
55
|
+
font-weight: normal;
|
|
56
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
const StyledContactInfo = styled(ContactInfo)`
|
|
60
|
+
font-size: 11pt;
|
|
61
|
+
text-align: center;
|
|
62
|
+
|
|
63
|
+
a {
|
|
64
|
+
font-size: 11pt;
|
|
65
|
+
color: #000000;
|
|
66
|
+
text-decoration: underline;
|
|
67
|
+
}
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
const Summary = styled.p`
|
|
71
|
+
font-size: 12pt;
|
|
72
|
+
line-height: 1.4;
|
|
73
|
+
color: #000000;
|
|
74
|
+
margin: 12pt 0 0 0;
|
|
75
|
+
text-align: left;
|
|
76
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
77
|
+
`;
|
|
78
|
+
|
|
79
|
+
const StyledSectionTitle = styled(SectionTitle)`
|
|
80
|
+
font-size: 14pt;
|
|
81
|
+
font-weight: bold;
|
|
82
|
+
color: #000000;
|
|
83
|
+
margin: 18pt 0 12pt 0;
|
|
84
|
+
padding-bottom: 4pt;
|
|
85
|
+
border-bottom: 1pt solid #000000;
|
|
86
|
+
text-transform: uppercase;
|
|
87
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
88
|
+
`;
|
|
89
|
+
|
|
90
|
+
const WorkItem = styled.div`
|
|
91
|
+
margin-bottom: 18pt;
|
|
92
|
+
page-break-inside: avoid;
|
|
93
|
+
|
|
94
|
+
&:last-child {
|
|
95
|
+
margin-bottom: 0;
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
|
|
99
|
+
const WorkHeader = styled.div`
|
|
100
|
+
margin-bottom: 6pt;
|
|
101
|
+
`;
|
|
102
|
+
|
|
103
|
+
const Position = styled.h3`
|
|
104
|
+
font-size: 13pt;
|
|
105
|
+
font-weight: bold;
|
|
106
|
+
color: #000000;
|
|
107
|
+
margin: 0 0 3pt 0;
|
|
108
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
109
|
+
`;
|
|
110
|
+
|
|
111
|
+
const Company = styled.div`
|
|
112
|
+
font-size: 12pt;
|
|
113
|
+
color: #000000;
|
|
114
|
+
font-weight: normal;
|
|
115
|
+
margin-bottom: 3pt;
|
|
116
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
117
|
+
`;
|
|
118
|
+
|
|
119
|
+
const DateText = styled.div`
|
|
120
|
+
font-size: 11pt;
|
|
121
|
+
color: #111827;
|
|
122
|
+
font-weight: normal;
|
|
123
|
+
font-style: italic;
|
|
124
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
125
|
+
`;
|
|
126
|
+
|
|
127
|
+
const WorkSummary = styled.p`
|
|
128
|
+
margin: 6pt 0;
|
|
129
|
+
color: #000000;
|
|
130
|
+
line-height: 1.4;
|
|
131
|
+
font-size: 12pt;
|
|
132
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
133
|
+
`;
|
|
134
|
+
|
|
135
|
+
const Highlights = styled.ul`
|
|
136
|
+
margin: 6pt 0 0 18pt;
|
|
137
|
+
padding: 0;
|
|
138
|
+
list-style-type: disc;
|
|
139
|
+
|
|
140
|
+
li {
|
|
141
|
+
margin: 3pt 0;
|
|
142
|
+
color: #000000;
|
|
143
|
+
line-height: 1.4;
|
|
144
|
+
font-size: 12pt;
|
|
145
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
146
|
+
}
|
|
147
|
+
`;
|
|
148
|
+
|
|
149
|
+
const EducationItem = styled.div`
|
|
150
|
+
margin-bottom: 12pt;
|
|
151
|
+
page-break-inside: avoid;
|
|
152
|
+
|
|
153
|
+
&:last-child {
|
|
154
|
+
margin-bottom: 0;
|
|
155
|
+
}
|
|
156
|
+
`;
|
|
157
|
+
|
|
158
|
+
const Institution = styled.h3`
|
|
159
|
+
font-size: 13pt;
|
|
160
|
+
font-weight: bold;
|
|
161
|
+
color: #000000;
|
|
162
|
+
margin: 0 0 3pt 0;
|
|
163
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
164
|
+
`;
|
|
165
|
+
|
|
166
|
+
const Degree = styled.div`
|
|
167
|
+
font-size: 12pt;
|
|
168
|
+
color: #000000;
|
|
169
|
+
margin-bottom: 3pt;
|
|
170
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
171
|
+
`;
|
|
172
|
+
|
|
173
|
+
const EducationDate = styled.div`
|
|
174
|
+
font-size: 11pt;
|
|
175
|
+
color: #111827;
|
|
176
|
+
font-style: italic;
|
|
177
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
178
|
+
`;
|
|
179
|
+
|
|
180
|
+
const SkillsList = styled.div`
|
|
181
|
+
margin-bottom: 12pt;
|
|
182
|
+
|
|
183
|
+
&:last-child {
|
|
184
|
+
margin-bottom: 0;
|
|
185
|
+
}
|
|
186
|
+
`;
|
|
187
|
+
|
|
188
|
+
const SkillName = styled.h4`
|
|
189
|
+
font-size: 12pt;
|
|
190
|
+
font-weight: bold;
|
|
191
|
+
color: #000000;
|
|
192
|
+
margin: 0 0 3pt 0;
|
|
193
|
+
display: inline;
|
|
194
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
195
|
+
`;
|
|
196
|
+
|
|
197
|
+
const SkillTags = styled.span`
|
|
198
|
+
font-size: 12pt;
|
|
199
|
+
color: #000000;
|
|
200
|
+
font-weight: normal;
|
|
201
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
202
|
+
`;
|
|
203
|
+
|
|
204
|
+
const SimpleList = styled.div`
|
|
205
|
+
margin-bottom: 12pt;
|
|
206
|
+
|
|
207
|
+
&:last-child {
|
|
208
|
+
margin-bottom: 0;
|
|
209
|
+
}
|
|
210
|
+
`;
|
|
211
|
+
|
|
212
|
+
const ListItemTitle = styled.h4`
|
|
213
|
+
font-size: 12pt;
|
|
214
|
+
font-weight: bold;
|
|
215
|
+
color: #000000;
|
|
216
|
+
margin: 0 0 3pt 0;
|
|
217
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
218
|
+
`;
|
|
219
|
+
|
|
220
|
+
const ListItemText = styled.p`
|
|
221
|
+
font-size: 12pt;
|
|
222
|
+
color: #000000;
|
|
223
|
+
margin: 3pt 0;
|
|
224
|
+
line-height: 1.4;
|
|
225
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
226
|
+
`;
|
|
227
|
+
|
|
228
|
+
// Export styled components for use in child components
|
|
229
|
+
export {
|
|
230
|
+
StyledSectionTitle,
|
|
231
|
+
WorkItem,
|
|
232
|
+
WorkHeader,
|
|
233
|
+
Position,
|
|
234
|
+
Company,
|
|
235
|
+
DateText,
|
|
236
|
+
WorkSummary,
|
|
237
|
+
Highlights,
|
|
238
|
+
EducationItem,
|
|
239
|
+
Institution,
|
|
240
|
+
Degree,
|
|
241
|
+
EducationDate,
|
|
242
|
+
SkillsList,
|
|
243
|
+
SkillName,
|
|
244
|
+
SkillTags,
|
|
245
|
+
SimpleList,
|
|
246
|
+
ListItemTitle,
|
|
247
|
+
ListItemText,
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
function Resume({ resume }) {
|
|
251
|
+
const {
|
|
252
|
+
basics = {},
|
|
253
|
+
work = [],
|
|
254
|
+
education = [],
|
|
255
|
+
skills = [],
|
|
256
|
+
projects = [],
|
|
257
|
+
volunteer = [],
|
|
258
|
+
awards = [],
|
|
259
|
+
publications = [],
|
|
260
|
+
languages = [],
|
|
261
|
+
interests = [],
|
|
262
|
+
references = [],
|
|
263
|
+
} = resume;
|
|
264
|
+
|
|
265
|
+
return (
|
|
266
|
+
<Layout>
|
|
267
|
+
<Header>
|
|
268
|
+
<Name>{basics.name}</Name>
|
|
269
|
+
{basics.label && <Label>{basics.label}</Label>}
|
|
270
|
+
<StyledContactInfo basics={basics} />
|
|
271
|
+
</Header>
|
|
272
|
+
|
|
273
|
+
{basics.summary && (
|
|
274
|
+
<Section>
|
|
275
|
+
<StyledSectionTitle>Professional Summary</StyledSectionTitle>
|
|
276
|
+
<Summary>{basics.summary}</Summary>
|
|
277
|
+
</Section>
|
|
278
|
+
)}
|
|
279
|
+
|
|
280
|
+
<WorkSection work={work} />
|
|
281
|
+
<EducationSection education={education} />
|
|
282
|
+
<SkillsSection skills={skills} />
|
|
283
|
+
<ProjectsSection projects={projects} />
|
|
284
|
+
<VolunteerSection volunteer={volunteer} />
|
|
285
|
+
<AwardsSection awards={awards} />
|
|
286
|
+
<PublicationsSection publications={publications} />
|
|
287
|
+
<LanguagesSection languages={languages} />
|
|
288
|
+
<InterestsSection interests={interests} />
|
|
289
|
+
<ReferencesSection references={references} />
|
|
290
|
+
</Layout>
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export default Resume;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Section, DateRange } from '@resume/core';
|
|
3
|
+
import {
|
|
4
|
+
StyledSectionTitle,
|
|
5
|
+
EducationItem,
|
|
6
|
+
Institution,
|
|
7
|
+
Degree,
|
|
8
|
+
EducationDate,
|
|
9
|
+
} from '../Resume.jsx';
|
|
10
|
+
|
|
11
|
+
export function EducationSection({ education }) {
|
|
12
|
+
if (!education?.length) return null;
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<Section>
|
|
16
|
+
<StyledSectionTitle>Education</StyledSectionTitle>
|
|
17
|
+
{education.map((edu, index) => (
|
|
18
|
+
<EducationItem key={index}>
|
|
19
|
+
<Institution>{edu.institution}</Institution>
|
|
20
|
+
<Degree>
|
|
21
|
+
{edu.studyType} in {edu.area}
|
|
22
|
+
{edu.score && ` - ${edu.score}`}
|
|
23
|
+
</Degree>
|
|
24
|
+
{(edu.startDate || edu.endDate) && (
|
|
25
|
+
<EducationDate>
|
|
26
|
+
<DateRange startDate={edu.startDate} endDate={edu.endDate} />
|
|
27
|
+
</EducationDate>
|
|
28
|
+
)}
|
|
29
|
+
</EducationItem>
|
|
30
|
+
))}
|
|
31
|
+
</Section>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Section, DateRange } from '@resume/core';
|
|
3
|
+
import {
|
|
4
|
+
StyledSectionTitle,
|
|
5
|
+
WorkItem,
|
|
6
|
+
WorkHeader,
|
|
7
|
+
Position,
|
|
8
|
+
Company,
|
|
9
|
+
DateText,
|
|
10
|
+
WorkSummary,
|
|
11
|
+
Highlights,
|
|
12
|
+
SimpleList,
|
|
13
|
+
ListItemTitle,
|
|
14
|
+
ListItemText,
|
|
15
|
+
SkillsList,
|
|
16
|
+
SkillName,
|
|
17
|
+
SkillTags,
|
|
18
|
+
} from '../Resume.jsx';
|
|
19
|
+
|
|
20
|
+
export function ProjectsSection({ projects }) {
|
|
21
|
+
if (!projects?.length) return null;
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Section>
|
|
25
|
+
<StyledSectionTitle>Projects</StyledSectionTitle>
|
|
26
|
+
{projects.map((project, index) => (
|
|
27
|
+
<WorkItem key={index}>
|
|
28
|
+
<Position>{project.name}</Position>
|
|
29
|
+
{project.description && (
|
|
30
|
+
<WorkSummary>{project.description}</WorkSummary>
|
|
31
|
+
)}
|
|
32
|
+
{project.highlights?.length > 0 && (
|
|
33
|
+
<Highlights>
|
|
34
|
+
{project.highlights.map((highlight, i) => (
|
|
35
|
+
<li key={i}>{highlight}</li>
|
|
36
|
+
))}
|
|
37
|
+
</Highlights>
|
|
38
|
+
)}
|
|
39
|
+
</WorkItem>
|
|
40
|
+
))}
|
|
41
|
+
</Section>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function VolunteerSection({ volunteer }) {
|
|
46
|
+
if (!volunteer?.length) return null;
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<Section>
|
|
50
|
+
<StyledSectionTitle>Volunteer Experience</StyledSectionTitle>
|
|
51
|
+
{volunteer.map((vol, index) => (
|
|
52
|
+
<WorkItem key={index}>
|
|
53
|
+
<WorkHeader>
|
|
54
|
+
<Position>{vol.position}</Position>
|
|
55
|
+
{vol.organization && <Company>{vol.organization}</Company>}
|
|
56
|
+
{(vol.startDate || vol.endDate) && (
|
|
57
|
+
<DateText>
|
|
58
|
+
<DateRange startDate={vol.startDate} endDate={vol.endDate} />
|
|
59
|
+
</DateText>
|
|
60
|
+
)}
|
|
61
|
+
</WorkHeader>
|
|
62
|
+
{vol.summary && <WorkSummary>{vol.summary}</WorkSummary>}
|
|
63
|
+
{vol.highlights?.length > 0 && (
|
|
64
|
+
<Highlights>
|
|
65
|
+
{vol.highlights.map((highlight, i) => (
|
|
66
|
+
<li key={i}>{highlight}</li>
|
|
67
|
+
))}
|
|
68
|
+
</Highlights>
|
|
69
|
+
)}
|
|
70
|
+
</WorkItem>
|
|
71
|
+
))}
|
|
72
|
+
</Section>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function AwardsSection({ awards }) {
|
|
77
|
+
if (!awards?.length) return null;
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<Section>
|
|
81
|
+
<StyledSectionTitle>Awards and Honors</StyledSectionTitle>
|
|
82
|
+
{awards.map((award, index) => (
|
|
83
|
+
<SimpleList key={index}>
|
|
84
|
+
<ListItemTitle>{award.title}</ListItemTitle>
|
|
85
|
+
{award.awarder && (
|
|
86
|
+
<ListItemText>Awarded by: {award.awarder}</ListItemText>
|
|
87
|
+
)}
|
|
88
|
+
{award.date && <ListItemText>Date: {award.date}</ListItemText>}
|
|
89
|
+
{award.summary && <ListItemText>{award.summary}</ListItemText>}
|
|
90
|
+
</SimpleList>
|
|
91
|
+
))}
|
|
92
|
+
</Section>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function PublicationsSection({ publications }) {
|
|
97
|
+
if (!publications?.length) return null;
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<Section>
|
|
101
|
+
<StyledSectionTitle>Publications</StyledSectionTitle>
|
|
102
|
+
{publications.map((pub, index) => (
|
|
103
|
+
<SimpleList key={index}>
|
|
104
|
+
<ListItemTitle>{pub.name}</ListItemTitle>
|
|
105
|
+
{pub.publisher && (
|
|
106
|
+
<ListItemText>Publisher: {pub.publisher}</ListItemText>
|
|
107
|
+
)}
|
|
108
|
+
{pub.releaseDate && (
|
|
109
|
+
<ListItemText>Published: {pub.releaseDate}</ListItemText>
|
|
110
|
+
)}
|
|
111
|
+
{pub.summary && <ListItemText>{pub.summary}</ListItemText>}
|
|
112
|
+
</SimpleList>
|
|
113
|
+
))}
|
|
114
|
+
</Section>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function LanguagesSection({ languages }) {
|
|
119
|
+
if (!languages?.length) return null;
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<Section>
|
|
123
|
+
<StyledSectionTitle>Languages</StyledSectionTitle>
|
|
124
|
+
{languages.map((lang, index) => (
|
|
125
|
+
<SkillsList key={index}>
|
|
126
|
+
<SkillName>{lang.language}:</SkillName>{' '}
|
|
127
|
+
{lang.fluency && <SkillTags>{lang.fluency}</SkillTags>}
|
|
128
|
+
</SkillsList>
|
|
129
|
+
))}
|
|
130
|
+
</Section>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function InterestsSection({ interests }) {
|
|
135
|
+
if (!interests?.length) return null;
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<Section>
|
|
139
|
+
<StyledSectionTitle>Professional Interests</StyledSectionTitle>
|
|
140
|
+
{interests.map((interest, index) => (
|
|
141
|
+
<SkillsList key={index}>
|
|
142
|
+
<SkillName>{interest.name}</SkillName>
|
|
143
|
+
{interest.keywords?.length > 0 && (
|
|
144
|
+
<>
|
|
145
|
+
: <SkillTags>{interest.keywords.join(', ')}</SkillTags>
|
|
146
|
+
</>
|
|
147
|
+
)}
|
|
148
|
+
</SkillsList>
|
|
149
|
+
))}
|
|
150
|
+
</Section>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function ReferencesSection({ references }) {
|
|
155
|
+
if (!references?.length) return null;
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<Section>
|
|
159
|
+
<StyledSectionTitle>References</StyledSectionTitle>
|
|
160
|
+
{references.map((ref, index) => (
|
|
161
|
+
<SimpleList key={index}>
|
|
162
|
+
<ListItemTitle>{ref.name}</ListItemTitle>
|
|
163
|
+
{ref.reference && <ListItemText>{ref.reference}</ListItemText>}
|
|
164
|
+
</SimpleList>
|
|
165
|
+
))}
|
|
166
|
+
</Section>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Section } from '@resume/core';
|
|
3
|
+
import {
|
|
4
|
+
StyledSectionTitle,
|
|
5
|
+
SkillsList,
|
|
6
|
+
SkillName,
|
|
7
|
+
SkillTags,
|
|
8
|
+
} from '../Resume.jsx';
|
|
9
|
+
|
|
10
|
+
export function SkillsSection({ skills }) {
|
|
11
|
+
if (!skills?.length) return null;
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<Section>
|
|
15
|
+
<StyledSectionTitle>Professional Skills</StyledSectionTitle>
|
|
16
|
+
{skills.map((skill, index) => (
|
|
17
|
+
<SkillsList key={index}>
|
|
18
|
+
<SkillName>{skill.name}:</SkillName>{' '}
|
|
19
|
+
{skill.keywords?.length > 0 && (
|
|
20
|
+
<SkillTags>{skill.keywords.join(', ')}</SkillTags>
|
|
21
|
+
)}
|
|
22
|
+
</SkillsList>
|
|
23
|
+
))}
|
|
24
|
+
</Section>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Section, DateRange } from '@resume/core';
|
|
3
|
+
import {
|
|
4
|
+
StyledSectionTitle,
|
|
5
|
+
WorkItem,
|
|
6
|
+
WorkHeader,
|
|
7
|
+
Position,
|
|
8
|
+
Company,
|
|
9
|
+
DateText,
|
|
10
|
+
WorkSummary,
|
|
11
|
+
Highlights,
|
|
12
|
+
} from '../Resume.jsx';
|
|
13
|
+
|
|
14
|
+
export function WorkSection({ work }) {
|
|
15
|
+
if (!work?.length) return null;
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<Section>
|
|
19
|
+
<StyledSectionTitle>Professional Experience</StyledSectionTitle>
|
|
20
|
+
{work.map((job, index) => (
|
|
21
|
+
<WorkItem key={index}>
|
|
22
|
+
<WorkHeader>
|
|
23
|
+
<Position>{job.position}</Position>
|
|
24
|
+
{job.name && <Company>{job.name}</Company>}
|
|
25
|
+
{(job.startDate || job.endDate) && (
|
|
26
|
+
<DateText>
|
|
27
|
+
<DateRange startDate={job.startDate} endDate={job.endDate} />
|
|
28
|
+
</DateText>
|
|
29
|
+
)}
|
|
30
|
+
</WorkHeader>
|
|
31
|
+
{job.summary && <WorkSummary>{job.summary}</WorkSummary>}
|
|
32
|
+
{job.highlights?.length > 0 && (
|
|
33
|
+
<Highlights>
|
|
34
|
+
{job.highlights.map((highlight, i) => (
|
|
35
|
+
<li key={i}>{highlight}</li>
|
|
36
|
+
))}
|
|
37
|
+
</Highlights>
|
|
38
|
+
)}
|
|
39
|
+
</WorkItem>
|
|
40
|
+
))}
|
|
41
|
+
</Section>
|
|
42
|
+
);
|
|
43
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { renderToString } from 'react-dom/server';
|
|
3
|
+
import { ServerStyleSheet } from 'styled-components';
|
|
4
|
+
import Resume from './Resume.jsx';
|
|
5
|
+
|
|
6
|
+
export function render(resume) {
|
|
7
|
+
const sheet = new ServerStyleSheet();
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
const html = renderToString(
|
|
11
|
+
sheet.collectStyles(<Resume resume={resume} />)
|
|
12
|
+
);
|
|
13
|
+
const styles = sheet.getStyleTags();
|
|
14
|
+
|
|
15
|
+
return `<!DOCTYPE html>
|
|
16
|
+
<html lang="en">
|
|
17
|
+
<head>
|
|
18
|
+
<meta charset="UTF-8">
|
|
19
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
20
|
+
<title>${resume.basics?.name || 'Resume'} - Resume</title>
|
|
21
|
+
${styles}
|
|
22
|
+
<style>
|
|
23
|
+
* {
|
|
24
|
+
box-sizing: border-box;
|
|
25
|
+
margin: 0;
|
|
26
|
+
padding: 0;
|
|
27
|
+
}
|
|
28
|
+
body {
|
|
29
|
+
margin: 0;
|
|
30
|
+
padding: 0;
|
|
31
|
+
background: #ffffff;
|
|
32
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
33
|
+
}
|
|
34
|
+
@media print {
|
|
35
|
+
body {
|
|
36
|
+
background: white;
|
|
37
|
+
}
|
|
38
|
+
@page {
|
|
39
|
+
margin: 1in;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
</style>
|
|
43
|
+
</head>
|
|
44
|
+
<body>
|
|
45
|
+
${html}
|
|
46
|
+
</body>
|
|
47
|
+
</html>`;
|
|
48
|
+
} finally {
|
|
49
|
+
sheet.seal();
|
|
50
|
+
}
|
|
51
|
+
}
|
package/src/styles.js
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
import { SectionTitle, ContactInfo } from '@resume/core';
|
|
3
|
+
|
|
4
|
+
export const Layout = styled.div`
|
|
5
|
+
max-width: 8.5in;
|
|
6
|
+
margin: 0 auto;
|
|
7
|
+
padding: 1in;
|
|
8
|
+
background: #ffffff;
|
|
9
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
10
|
+
font-size: 12pt;
|
|
11
|
+
color: #000000;
|
|
12
|
+
line-height: 1.4;
|
|
13
|
+
|
|
14
|
+
@media print {
|
|
15
|
+
padding: 0;
|
|
16
|
+
margin: 0;
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
export const Header = styled.header`
|
|
21
|
+
text-align: center;
|
|
22
|
+
margin-bottom: 24pt;
|
|
23
|
+
padding-bottom: 12pt;
|
|
24
|
+
border-bottom: 2pt solid #000000;
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
export const Name = styled.h1`
|
|
28
|
+
font-size: 18pt;
|
|
29
|
+
font-weight: bold;
|
|
30
|
+
color: #000000;
|
|
31
|
+
margin: 0 0 6pt 0;
|
|
32
|
+
letter-spacing: 0;
|
|
33
|
+
text-transform: uppercase;
|
|
34
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
export const Label = styled.div`
|
|
38
|
+
font-size: 12pt;
|
|
39
|
+
color: #000000;
|
|
40
|
+
margin-bottom: 8pt;
|
|
41
|
+
font-weight: normal;
|
|
42
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
export const StyledContactInfo = styled(ContactInfo)`
|
|
46
|
+
font-size: 11pt;
|
|
47
|
+
text-align: center;
|
|
48
|
+
|
|
49
|
+
a {
|
|
50
|
+
font-size: 11pt;
|
|
51
|
+
color: #000000;
|
|
52
|
+
text-decoration: underline;
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
export const Summary = styled.p`
|
|
57
|
+
font-size: 12pt;
|
|
58
|
+
line-height: 1.4;
|
|
59
|
+
color: #000000;
|
|
60
|
+
margin: 12pt 0 0 0;
|
|
61
|
+
text-align: left;
|
|
62
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
export const StyledSectionTitle = styled(SectionTitle)`
|
|
66
|
+
font-size: 14pt;
|
|
67
|
+
font-weight: bold;
|
|
68
|
+
color: #000000;
|
|
69
|
+
margin: 18pt 0 12pt 0;
|
|
70
|
+
padding-bottom: 4pt;
|
|
71
|
+
border-bottom: 1pt solid #000000;
|
|
72
|
+
text-transform: uppercase;
|
|
73
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
export const WorkItem = styled.div`
|
|
77
|
+
margin-bottom: 18pt;
|
|
78
|
+
page-break-inside: avoid;
|
|
79
|
+
|
|
80
|
+
&:last-child {
|
|
81
|
+
margin-bottom: 0;
|
|
82
|
+
}
|
|
83
|
+
`;
|
|
84
|
+
|
|
85
|
+
export const WorkHeader = styled.div`
|
|
86
|
+
margin-bottom: 6pt;
|
|
87
|
+
`;
|
|
88
|
+
|
|
89
|
+
export const Position = styled.h3`
|
|
90
|
+
font-size: 13pt;
|
|
91
|
+
font-weight: bold;
|
|
92
|
+
color: #000000;
|
|
93
|
+
margin: 0 0 3pt 0;
|
|
94
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
95
|
+
`;
|
|
96
|
+
|
|
97
|
+
export const Company = styled.div`
|
|
98
|
+
font-size: 12pt;
|
|
99
|
+
color: #000000;
|
|
100
|
+
font-weight: normal;
|
|
101
|
+
margin-bottom: 3pt;
|
|
102
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
103
|
+
`;
|
|
104
|
+
|
|
105
|
+
export const DateText = styled.div`
|
|
106
|
+
font-size: 11pt;
|
|
107
|
+
color: #111827;
|
|
108
|
+
font-weight: normal;
|
|
109
|
+
font-style: italic;
|
|
110
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
111
|
+
`;
|
|
112
|
+
|
|
113
|
+
export const WorkSummary = styled.p`
|
|
114
|
+
margin: 6pt 0;
|
|
115
|
+
color: #000000;
|
|
116
|
+
line-height: 1.4;
|
|
117
|
+
font-size: 12pt;
|
|
118
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
119
|
+
`;
|
|
120
|
+
|
|
121
|
+
export const Highlights = styled.ul`
|
|
122
|
+
margin: 6pt 0 0 18pt;
|
|
123
|
+
padding: 0;
|
|
124
|
+
list-style-type: disc;
|
|
125
|
+
|
|
126
|
+
li {
|
|
127
|
+
margin: 3pt 0;
|
|
128
|
+
color: #000000;
|
|
129
|
+
line-height: 1.4;
|
|
130
|
+
font-size: 12pt;
|
|
131
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
132
|
+
}
|
|
133
|
+
`;
|
|
134
|
+
|
|
135
|
+
export const EducationItem = styled.div`
|
|
136
|
+
margin-bottom: 12pt;
|
|
137
|
+
page-break-inside: avoid;
|
|
138
|
+
|
|
139
|
+
&:last-child {
|
|
140
|
+
margin-bottom: 0;
|
|
141
|
+
}
|
|
142
|
+
`;
|
|
143
|
+
|
|
144
|
+
export const Institution = styled.h3`
|
|
145
|
+
font-size: 13pt;
|
|
146
|
+
font-weight: bold;
|
|
147
|
+
color: #000000;
|
|
148
|
+
margin: 0 0 3pt 0;
|
|
149
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
150
|
+
`;
|
|
151
|
+
|
|
152
|
+
export const Degree = styled.div`
|
|
153
|
+
font-size: 12pt;
|
|
154
|
+
color: #000000;
|
|
155
|
+
margin-bottom: 3pt;
|
|
156
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
157
|
+
`;
|
|
158
|
+
|
|
159
|
+
export const EducationDate = styled.div`
|
|
160
|
+
font-size: 11pt;
|
|
161
|
+
color: #111827;
|
|
162
|
+
font-style: italic;
|
|
163
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
164
|
+
`;
|
|
165
|
+
|
|
166
|
+
export const SkillsList = styled.div`
|
|
167
|
+
margin-bottom: 12pt;
|
|
168
|
+
|
|
169
|
+
&:last-child {
|
|
170
|
+
margin-bottom: 0;
|
|
171
|
+
}
|
|
172
|
+
`;
|
|
173
|
+
|
|
174
|
+
export const SkillName = styled.h4`
|
|
175
|
+
font-size: 12pt;
|
|
176
|
+
font-weight: bold;
|
|
177
|
+
color: #000000;
|
|
178
|
+
margin: 0 0 3pt 0;
|
|
179
|
+
display: inline;
|
|
180
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
181
|
+
`;
|
|
182
|
+
|
|
183
|
+
export const SkillTags = styled.span`
|
|
184
|
+
font-size: 12pt;
|
|
185
|
+
color: #000000;
|
|
186
|
+
font-weight: normal;
|
|
187
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
188
|
+
`;
|
|
189
|
+
|
|
190
|
+
export const SimpleList = styled.div`
|
|
191
|
+
margin-bottom: 12pt;
|
|
192
|
+
|
|
193
|
+
&:last-child {
|
|
194
|
+
margin-bottom: 0;
|
|
195
|
+
}
|
|
196
|
+
`;
|
|
197
|
+
|
|
198
|
+
export const ListItemTitle = styled.h4`
|
|
199
|
+
font-size: 12pt;
|
|
200
|
+
font-weight: bold;
|
|
201
|
+
color: #000000;
|
|
202
|
+
margin: 0 0 3pt 0;
|
|
203
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
204
|
+
`;
|
|
205
|
+
|
|
206
|
+
export const ListItemText = styled.p`
|
|
207
|
+
font-size: 12pt;
|
|
208
|
+
color: #000000;
|
|
209
|
+
margin: 3pt 0;
|
|
210
|
+
line-height: 1.4;
|
|
211
|
+
font-family: 'Times New Roman', Georgia, serif;
|
|
212
|
+
`;
|