@jsonresume/jsonresume-theme-professional 1.0.15 → 1.0.18

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/.eslintrc.js ADDED
@@ -0,0 +1,8 @@
1
+ /* eslint-disable */
2
+
3
+ module.exports = {
4
+ root: true,
5
+ extends: ['@repo/eslint-config-custom'],
6
+ parser: '@typescript-eslint/parser',
7
+ rules: {},
8
+ };
@@ -0,0 +1,5 @@
1
+
2
+ > jsonresume-theme-professional@0.0.0 lint /home/ajax/repos/jsonresume.org/packages/jsonresume-theme-professional
3
+ > eslint .
4
+
5
+ Pages directory cannot be found at /home/ajax/repos/jsonresume.org/packages/jsonresume-theme-professional/pages or /home/ajax/repos/jsonresume.org/packages/jsonresume-theme-professional/src/pages. If using a custom path, please configure with the `no-html-link-for-pages` rule in your eslint config file.
package/README.md CHANGED
@@ -4,6 +4,3 @@ figure out a way to give a lot of credit to
4
4
 
5
5
  https://github.com/BartoszJarocki/cv
6
6
  https://github.com/midudev/minimalist-portfolio-json
7
-
8
-
9
- npm publish --access=public
package/package.json CHANGED
@@ -1,45 +1,22 @@
1
1
  {
2
- "name": "@jsonresume/jsonresume-theme-professional",
3
- "version": "1.0.15",
4
2
  "private": false,
3
+ "name": "@jsonresume/jsonresume-theme-professional",
4
+ "version": "1.0.18",
5
+ "main": "./src/index.js",
5
6
  "license": "MIT",
6
- "type": "module",
7
- "module": "dist/es/index.mjs",
8
- "exports": {
9
- ".": {
10
- "import": "./dist/es/index.mjs"
11
- },
12
- "./package.json": "./package.json"
13
- },
14
- "files": [
15
- "dist"
16
- ],
17
7
  "devDependencies": {
18
- "eslint-config-custom": "workspace:^"
8
+ "@repo/eslint-config-custom": "workspace:^",
9
+ "react": "^18",
10
+ "styled-components": "^6"
19
11
  },
20
12
  "peerDependencies": {
21
- "react": "^18.3.1",
22
13
  "styled-components": "^6"
23
14
  },
24
15
  "scripts": {
25
- "lint": "eslint .",
26
- "build": "rollup -c",
27
- "prepublishOnly": "npm run build"
16
+ "lint": "eslint ."
28
17
  },
29
18
  "dependencies": {
30
- "@babel/cli": "^7.24.7",
31
- "@babel/core": "^7.24.6",
32
- "@babel/preset-env": "^7.23.6",
33
- "@babel/preset-react": "^7.24.7",
34
- "@rollup/plugin-babel": "^6.0.4",
35
- "@rollup/plugin-commonjs": "^26.0.1",
36
- "@rollup/plugin-node-resolve": "^15.2.3",
37
- "@rollup/plugin-replace": "^5.0.7",
38
- "babel-plugin-styled-components": "^2.1.4",
39
- "babel-preset-react": "^6.24.1",
40
19
  "prismjs": "^1.29.0",
41
- "react-dom": "^18.3.1",
42
- "react-icons": "^5.0.1",
43
- "rollup": "^4.18.0"
20
+ "react-icons": "^5.0.1"
44
21
  }
45
22
  }
package/src/index.js ADDED
@@ -0,0 +1,98 @@
1
+ import { renderToString } from 'react-dom/server';
2
+ import { ServerStyleSheet } from 'styled-components';
3
+ import Resume from './ui/Resume';
4
+
5
+ export const render = (resume) => {
6
+ const sheet = new ServerStyleSheet();
7
+ const html = renderToString(sheet.collectStyles(<Resume resume={resume} />));
8
+ const styles = sheet.getStyleTags();
9
+ return `<!DOCTYPE html><head>
10
+ <title>${resume.basics.name} - Resume</title>
11
+ <meta charset="utf-8">
12
+ <meta name="viewport" content="width=device-width, initial-scale=1"/>
13
+ <style>
14
+ @font-face {
15
+ font-family: LatinModern;
16
+ font-style: normal;
17
+ font-weight: normal;
18
+ src: url("/fonts/lmroman10-regular.otf") format("opentype");
19
+ }
20
+
21
+ @font-face {
22
+ font-family: LatinModern;
23
+ font-weight: bold;
24
+ src: url("/fonts/lmroman10-bold.otf") format("opentype");
25
+ }
26
+
27
+ @font-face {
28
+ font-family: LatinModern;
29
+ font-style: italic;
30
+ src: url("/fonts/lmroman10-italic.otf") format("opentype");
31
+ }
32
+
33
+ @font-face {
34
+ font-family: LatinModernSans;
35
+ font-style: normal;
36
+ font-weight: normal;
37
+ src: url("/fonts/lmsans10-regular.otf") format("opentype");
38
+ }
39
+
40
+ @font-face {
41
+ font-family: LatinModernSans;
42
+ font-weight: bold;
43
+ src: url("/fonts/lmsans10-bold.otf") format("opentype");
44
+ }
45
+
46
+ @font-face {
47
+ font-family: LatinModernSans;
48
+ font-style: italic;
49
+ src: url("/fonts/lmsans10-italic.otf") format("opentype");
50
+ }
51
+
52
+ html {
53
+ font-family:LatinModern, "Courier New", monospace;
54
+ background: #fff;
55
+ font-size: 10px;
56
+ }
57
+
58
+ h2 {
59
+ font-size: 1.65rem;
60
+ }
61
+
62
+ p {
63
+ padding: 0;
64
+ margin: 0;
65
+ }
66
+
67
+ p, li {
68
+ font-size: 1.4rem;
69
+ line-height: 1.5rem;
70
+ }
71
+
72
+ .secondary {
73
+ color: #111;
74
+ }
75
+
76
+ a {
77
+ text-decoration: none;
78
+ }
79
+
80
+ ul {
81
+ list-style: none;
82
+ margin: 0;
83
+ padding: 0;
84
+ }
85
+
86
+ *,
87
+ *::before,
88
+ *::after {
89
+ box-sizing: border-box;
90
+ }
91
+
92
+
93
+
94
+ </style>
95
+ ${styles}</head><body>${html}</body></html>`;
96
+ };
97
+
98
+ export { Resume };
@@ -0,0 +1,28 @@
1
+ import Section from './Section';
2
+ import Experience from './Experience';
3
+
4
+ const Awards = ({ awards }) => {
5
+ if (!awards) {
6
+ return null;
7
+ }
8
+
9
+ return (
10
+ <div>
11
+ <Section title="Awards">
12
+ {awards.map((a, key) => {
13
+ return (
14
+ <Experience
15
+ title={a.title}
16
+ subTitle={a.awarder}
17
+ date={a.date}
18
+ summary={a.summary}
19
+ key={key}
20
+ />
21
+ );
22
+ })}
23
+ </Section>
24
+ </div>
25
+ );
26
+ };
27
+
28
+ export default Awards;
@@ -0,0 +1,27 @@
1
+ import Section from './Section';
2
+ import Experience from './Experience';
3
+
4
+ const Certificates = ({ certificates }) => {
5
+ if (!certificates) {
6
+ return null;
7
+ }
8
+
9
+ return (
10
+ <div>
11
+ <Section title="Certificates">
12
+ {certificates.map((c, key) => {
13
+ return (
14
+ <Experience
15
+ title={c.name}
16
+ subTitle={c.issuer}
17
+ date={c.date}
18
+ key={key}
19
+ />
20
+ );
21
+ })}
22
+ </Section>
23
+ </div>
24
+ );
25
+ };
26
+
27
+ export default Certificates;
package/src/ui/Date.js ADDED
@@ -0,0 +1,21 @@
1
+ import styled from 'styled-components';
2
+
3
+ const Text = styled.div`
4
+ font-style: italic;
5
+ font-size: 1.4rem;
6
+ `;
7
+
8
+ const DateComponent = ({ date }) => {
9
+ if (!date) {
10
+ return <Text>Present</Text>;
11
+ }
12
+
13
+ const fullDate = new Date(date);
14
+
15
+ const options = { year: 'numeric', month: 'long' };
16
+ const formattedDate = fullDate.toLocaleDateString('en-US', options);
17
+
18
+ return <Text>{formattedDate ?? 'Present'}</Text>;
19
+ };
20
+
21
+ export default DateComponent;
@@ -0,0 +1,20 @@
1
+ import styled from 'styled-components';
2
+ import Date from './Date';
3
+
4
+ const Range = styled.div`
5
+ display: flex;
6
+ font-style: italic;
7
+ font-size: 13px;
8
+ `;
9
+
10
+ const DateRange = ({ startDate, endDate }) => {
11
+ return (
12
+ <Range>
13
+ <Date date={startDate} />
14
+ &nbsp;—&nbsp;
15
+ <Date date={endDate} />
16
+ </Range>
17
+ );
18
+ };
19
+
20
+ export default DateRange;
@@ -0,0 +1,35 @@
1
+ import Section from './Section';
2
+ import Experience from './Experience';
3
+
4
+ const Education = ({ education }) => {
5
+ if (!education) {
6
+ return null;
7
+ }
8
+
9
+ return (
10
+ <div>
11
+ <Section title="Education">
12
+ {education.map((e, key) => {
13
+ let subTitle = e.area ? `${e.studyType} in ${e.area}` : e.studyType;
14
+
15
+ if (e.score) {
16
+ subTitle = `${subTitle} (${e.score})`;
17
+ }
18
+
19
+ return (
20
+ <Experience
21
+ title={e.institution}
22
+ subTitle={subTitle}
23
+ startDate={e.startDate}
24
+ endDate={e.endDate}
25
+ highlights={e.courses}
26
+ key={key}
27
+ />
28
+ );
29
+ })}
30
+ </Section>
31
+ </div>
32
+ );
33
+ };
34
+
35
+ export default Education;
@@ -0,0 +1,62 @@
1
+ import styled from 'styled-components';
2
+ import List from './List';
3
+ import DateRange from './DateRange';
4
+ import Date from './Date';
5
+
6
+ const Meta = styled.div`
7
+ display: flex;
8
+ justify-content: space-between;
9
+ margin-bottom: 2px;
10
+ `;
11
+
12
+ const Title = styled.div`
13
+ font-weight: 600;
14
+ font-size: 1.45rem;
15
+ margin-bottom: 3px;
16
+ `;
17
+
18
+ const SubTitle = styled.div`
19
+ font-style: italic;
20
+ font-size: 1.4rem;
21
+ margin-bottom: 3px;
22
+ `;
23
+
24
+ const Container = styled.div`
25
+ margin-bottom: 10px;
26
+ `;
27
+
28
+ const Summary = styled.p`
29
+ margin-bottom: 5px;
30
+ `;
31
+
32
+ const Experience = ({
33
+ title,
34
+ date,
35
+ startDate,
36
+ endDate,
37
+ subTitle,
38
+ summary,
39
+ highlights,
40
+ }) => {
41
+ return (
42
+ <Container>
43
+ <Meta>
44
+ <Title>{title}</Title>
45
+ <div className="secondary">
46
+ {date ? (
47
+ <Date date={date} />
48
+ ) : (
49
+ <DateRange startDate={startDate} endDate={endDate} />
50
+ )}
51
+ </div>
52
+ </Meta>
53
+ {subTitle && <SubTitle>{subTitle}</SubTitle>}
54
+ <div className="secondary">
55
+ {summary && <Summary>{summary}</Summary>}
56
+ <List items={highlights} />
57
+ </div>
58
+ </Container>
59
+ );
60
+ };
61
+
62
+ export default Experience;
package/src/ui/Hero.js ADDED
@@ -0,0 +1,120 @@
1
+ import styled from 'styled-components';
2
+ import {
3
+ FaMapPin,
4
+ FaEnvelope,
5
+ FaGithub,
6
+ FaTwitter,
7
+ FaPhoneAlt,
8
+ FaLink,
9
+ FaLinkedin,
10
+ } from 'react-icons/fa';
11
+ import Section from './Section';
12
+
13
+ const Title = styled.div`
14
+ font-size: 3rem;
15
+ text-align: center;
16
+ margin-top: 20px;
17
+ margin-bottom: 20px;
18
+ `;
19
+
20
+ const BasicInfo = styled.div`
21
+ display: flex;
22
+ gap: 10px 20px;
23
+ justify-content: center;
24
+ flex-wrap: wrap;
25
+ `;
26
+
27
+ const Info = styled.div`
28
+ display: flex;
29
+ align-items: center;
30
+ font-size: 1.5rem;
31
+ svg {
32
+ color: #000;
33
+ margin-right: 5px;
34
+ width: 10px;
35
+ }
36
+
37
+ a {
38
+ color: inherit;
39
+ text-decoration: none;
40
+ &:hover {
41
+ color: #000;
42
+ }
43
+ }
44
+ `;
45
+
46
+ const HeroComponent = ({ basics }) => {
47
+ const { name, url, location, profiles, phone, email } = basics;
48
+
49
+ const linkedin = profiles.find(
50
+ ({ network }) => network.toLowerCase() === 'linkedin'
51
+ );
52
+ const github = profiles.find(
53
+ ({ network }) => network.toLowerCase() === 'github'
54
+ );
55
+ const twitter = profiles.find(
56
+ ({ network }) => network.toLowerCase() === 'twitter'
57
+ );
58
+
59
+ return (
60
+ <Section>
61
+ <Title>{name}</Title>
62
+ <div className="secondary">
63
+ <BasicInfo>
64
+ {location && (
65
+ <Info>
66
+ <FaMapPin />
67
+ {location.city}, {location.countryCode}
68
+ </Info>
69
+ )}
70
+ {email && (
71
+ <Info>
72
+ <FaEnvelope />
73
+ {email}
74
+ </Info>
75
+ )}
76
+ {phone && (
77
+ <Info>
78
+ <FaPhoneAlt />
79
+ {phone}
80
+ </Info>
81
+ )}
82
+ {url && (
83
+ <Info>
84
+ <FaLink />
85
+ <a target="_blank" href={url}>
86
+ {url}
87
+ </a>
88
+ </Info>
89
+ )}
90
+ {linkedin && (
91
+ <Info>
92
+ <FaLinkedin />
93
+ <a href={`https://linkedin.com/in/${linkedin.username}`}>
94
+ {linkedin.username}
95
+ </a>
96
+ </Info>
97
+ )}
98
+ {github && (
99
+ <Info>
100
+ <FaGithub />
101
+ <a href={`https://github.com/${github.username}`}>
102
+ {github.username}
103
+ </a>
104
+ </Info>
105
+ )}
106
+ {twitter && (
107
+ <Info>
108
+ <FaTwitter />
109
+ <a href={`https://twitter.com/${twitter.username}`}>
110
+ {twitter.username}
111
+ </a>
112
+ </Info>
113
+ )}
114
+ </BasicInfo>
115
+ </div>
116
+ </Section>
117
+ );
118
+ };
119
+
120
+ export default HeroComponent;
@@ -0,0 +1,22 @@
1
+ import OneLineList from './OneLineList';
2
+ import Section from './Section';
3
+
4
+ const Interests = ({ interests }) => {
5
+ // check if interests is null, empty, empty string or empty array
6
+
7
+ if (!interests) {
8
+ return null;
9
+ }
10
+
11
+ return (
12
+ <div>
13
+ <Section title="Interests">
14
+ {interests.map((w, key) => {
15
+ return <OneLineList key={key} name={w.name} items={w.keywords} />;
16
+ })}
17
+ </Section>
18
+ </div>
19
+ );
20
+ };
21
+
22
+ export default Interests;
@@ -0,0 +1,23 @@
1
+ import OneLineList from './OneLineList';
2
+
3
+ import Section from './Section';
4
+
5
+ const Languages = ({ languages }) => {
6
+ if (!languages) {
7
+ return null;
8
+ }
9
+
10
+ return (
11
+ <div>
12
+ <Section title="Languages">
13
+ {languages.map((l, key) => {
14
+ return (
15
+ <OneLineList key={key} name={l.language} items={[l.fluency]} />
16
+ );
17
+ })}
18
+ </Section>
19
+ </div>
20
+ );
21
+ };
22
+
23
+ export default Languages;
package/src/ui/List.js ADDED
@@ -0,0 +1,29 @@
1
+ import styled from 'styled-components';
2
+
3
+ const ListContainer = styled.ul`
4
+ padding-left: 20px;
5
+ line-height: 16px;
6
+ li::before {
7
+ content: '•';
8
+ display: inline-block;
9
+ width: 1em;
10
+ margin-left: -1em;
11
+ line-height: 10px;
12
+ }
13
+ `;
14
+
15
+ const List = ({ items }) => {
16
+ if (!items) {
17
+ return null;
18
+ }
19
+
20
+ return (
21
+ <ListContainer>
22
+ {items.map((item) => (
23
+ <li key={item}>{item}</li>
24
+ ))}
25
+ </ListContainer>
26
+ );
27
+ };
28
+
29
+ export default List;
@@ -0,0 +1,30 @@
1
+ import styled from 'styled-components';
2
+
3
+ const Name = styled.div`
4
+ font-weight: 600;
5
+ font-size: 1.4rem;
6
+ `;
7
+
8
+ const List = styled.div`
9
+ font-size: 1.4rem;
10
+ margin-left: 5px;
11
+ `;
12
+
13
+ const Container = styled.div`
14
+ margin-bottom: 5px;
15
+ display: flex;
16
+ align-items: baseline;
17
+ `;
18
+
19
+ const OneLineList = ({ name, items }) => {
20
+ return (
21
+ <Container>
22
+ <Name>{name}:</Name>
23
+ <List>
24
+ <div class="secondary">{items?.join(', ')}</div>
25
+ </List>
26
+ </Container>
27
+ );
28
+ };
29
+
30
+ export default OneLineList;
@@ -0,0 +1,29 @@
1
+ import Section from './Section';
2
+ import Experience from './Experience';
3
+
4
+ const Work = ({ projects }) => {
5
+ if (!projects) {
6
+ return null;
7
+ }
8
+
9
+ return (
10
+ <div>
11
+ <Section title="Projects">
12
+ {projects.map((w, key) => {
13
+ return (
14
+ <Experience
15
+ title={w.name}
16
+ startDate={w.startDate}
17
+ endDate={w.endDate}
18
+ summary={w.description}
19
+ highlights={w.highlights}
20
+ key={key}
21
+ />
22
+ );
23
+ })}
24
+ </Section>
25
+ </div>
26
+ );
27
+ };
28
+
29
+ export default Work;
@@ -0,0 +1,28 @@
1
+ import Section from './Section';
2
+ import Experience from './Experience';
3
+
4
+ const Publications = ({ publications }) => {
5
+ if (!publications) {
6
+ return null;
7
+ }
8
+
9
+ return (
10
+ <div>
11
+ <Section title="Publications">
12
+ {publications.map((p, key) => {
13
+ return (
14
+ <Experience
15
+ title={p.name}
16
+ subTitle={p.publisher}
17
+ date={p.releaseDate}
18
+ summary={p.summary}
19
+ key={key}
20
+ />
21
+ );
22
+ })}
23
+ </Section>
24
+ </div>
25
+ );
26
+ };
27
+
28
+ export default Publications;
@@ -0,0 +1,33 @@
1
+ import styled from 'styled-components';
2
+ import Section from './Section';
3
+
4
+ const Name = styled.div`
5
+ font-weight: 600;
6
+ font-size: 1.4rem;
7
+ margin-bottom: 5px;
8
+ `;
9
+
10
+ const Reference = styled.p``;
11
+
12
+ const References = ({ references }) => {
13
+ if (!references) {
14
+ return null;
15
+ }
16
+
17
+ return (
18
+ <div>
19
+ <Section title="References">
20
+ {references.map((r, key) => {
21
+ return (
22
+ <div key={key} style={{ marginBottom: '15px' }}>
23
+ <Name>{r.name}</Name>
24
+ <Reference>{r.reference}</Reference>
25
+ </div>
26
+ );
27
+ })}
28
+ </Section>
29
+ </div>
30
+ );
31
+ };
32
+
33
+ export default References;