jsonresume-theme-desert-modern 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 +46 -0
- package/package.json +23 -0
- package/src/Resume.jsx +333 -0
- package/src/index.js +54 -0
- package/src/styles.js +244 -0
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Desert Modern - JSON Resume Theme
|
|
2
|
+
|
|
3
|
+
A warm minimalist JSON Resume theme inspired by desert landscapes and contemporary architecture. Designed for creative technologists, wellness professionals, and anyone who wants a calm, grounded presentation.
|
|
4
|
+
|
|
5
|
+
## Design Specification
|
|
6
|
+
|
|
7
|
+
- **Vibe:** Warm minimalism with sand-toned calm
|
|
8
|
+
- **Layout:** Single column with gentle vertical rhythm and thin separators
|
|
9
|
+
- **Typography:** Light sans-serif stack (Nunito, Inter) with generous letter spacing
|
|
10
|
+
- **Colors:** Accent `#d97706` (desert amber) on a soft cream background
|
|
11
|
+
- **Notes:** Ideal for portfolios with both creative and professional touchpoints
|
|
12
|
+
|
|
13
|
+
## Highlights
|
|
14
|
+
|
|
15
|
+
- Soft cream paper background with subtle shadowing for print-friendly warmth
|
|
16
|
+
- Thin amber dividers and section markers to reinforce the desert tone
|
|
17
|
+
- Balanced typography with lighter weights for headings and relaxed body copy
|
|
18
|
+
- Clean metadata layout prioritizing readability and ATS compatibility
|
|
19
|
+
|
|
20
|
+
## Supported JSON Resume Sections
|
|
21
|
+
|
|
22
|
+
All 12 standard sections render with consistent styling:
|
|
23
|
+
|
|
24
|
+
- Basics (name, contact, summary)
|
|
25
|
+
- Work
|
|
26
|
+
- Projects
|
|
27
|
+
- Education
|
|
28
|
+
- Skills
|
|
29
|
+
- Volunteer
|
|
30
|
+
- Awards
|
|
31
|
+
- Certifications
|
|
32
|
+
- Publications
|
|
33
|
+
- Languages
|
|
34
|
+
- Interests
|
|
35
|
+
- References
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install jsonresume-theme-desert-modern
|
|
41
|
+
jsonresume serve --theme desert-modern
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## License
|
|
45
|
+
|
|
46
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jsonresume-theme-desert-modern",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Warm minimalist resume theme inspired by desert modern aesthetics",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"jsonresume",
|
|
10
|
+
"theme",
|
|
11
|
+
"desert",
|
|
12
|
+
"minimalist",
|
|
13
|
+
"modern"
|
|
14
|
+
],
|
|
15
|
+
"peerDependencies": {
|
|
16
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
17
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"styled-components": "^6.1.19",
|
|
21
|
+
"@resume/core": "0.1.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/Resume.jsx
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DateRange } from '@resume/core';
|
|
3
|
+
import {
|
|
4
|
+
Layout,
|
|
5
|
+
Header,
|
|
6
|
+
Name,
|
|
7
|
+
Label,
|
|
8
|
+
StyledContactInfo,
|
|
9
|
+
Summary,
|
|
10
|
+
SectionBlock,
|
|
11
|
+
SectionHeading,
|
|
12
|
+
Entry,
|
|
13
|
+
EntryHeader,
|
|
14
|
+
EntryTitle,
|
|
15
|
+
EntrySubtitle,
|
|
16
|
+
EntryMeta,
|
|
17
|
+
EntrySummary,
|
|
18
|
+
BulletList,
|
|
19
|
+
SkillGrid,
|
|
20
|
+
SkillCard,
|
|
21
|
+
SkillTitle,
|
|
22
|
+
KeywordList,
|
|
23
|
+
Pill,
|
|
24
|
+
Anchor,
|
|
25
|
+
} from './styles';
|
|
26
|
+
|
|
27
|
+
const joinParts = (...parts) => parts.filter(Boolean).join(' • ');
|
|
28
|
+
|
|
29
|
+
const renderHighlights = (items) =>
|
|
30
|
+
items?.length ? (
|
|
31
|
+
<BulletList>
|
|
32
|
+
{items.map((text, index) => (
|
|
33
|
+
<li key={index}>{text}</li>
|
|
34
|
+
))}
|
|
35
|
+
</BulletList>
|
|
36
|
+
) : null;
|
|
37
|
+
|
|
38
|
+
function Resume({ resume }) {
|
|
39
|
+
const {
|
|
40
|
+
basics = {},
|
|
41
|
+
work = [],
|
|
42
|
+
education = [],
|
|
43
|
+
projects = [],
|
|
44
|
+
volunteer = [],
|
|
45
|
+
skills = [],
|
|
46
|
+
awards = [],
|
|
47
|
+
certificates = [],
|
|
48
|
+
publications = [],
|
|
49
|
+
languages = [],
|
|
50
|
+
interests = [],
|
|
51
|
+
references = [],
|
|
52
|
+
} = resume;
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<Layout>
|
|
56
|
+
<Header>
|
|
57
|
+
{basics.name && <Name>{basics.name}</Name>}
|
|
58
|
+
{basics.label && <Label>{basics.label}</Label>}
|
|
59
|
+
<StyledContactInfo basics={basics} />
|
|
60
|
+
{basics.summary && <Summary>{basics.summary}</Summary>}
|
|
61
|
+
</Header>
|
|
62
|
+
|
|
63
|
+
{work?.length > 0 && (
|
|
64
|
+
<SectionBlock>
|
|
65
|
+
<SectionHeading>Experience</SectionHeading>
|
|
66
|
+
{work.map((job, index) => (
|
|
67
|
+
<Entry key={index}>
|
|
68
|
+
<EntryHeader>
|
|
69
|
+
<div>
|
|
70
|
+
{job.position && <EntryTitle>{job.position}</EntryTitle>}
|
|
71
|
+
{job.name || job.location ? (
|
|
72
|
+
<EntrySubtitle>
|
|
73
|
+
{joinParts(job.name, job.location)}
|
|
74
|
+
</EntrySubtitle>
|
|
75
|
+
) : null}
|
|
76
|
+
</div>
|
|
77
|
+
{(job.startDate || job.endDate) && (
|
|
78
|
+
<EntryMeta>
|
|
79
|
+
<DateRange
|
|
80
|
+
startDate={job.startDate}
|
|
81
|
+
endDate={job.endDate}
|
|
82
|
+
/>
|
|
83
|
+
</EntryMeta>
|
|
84
|
+
)}
|
|
85
|
+
</EntryHeader>
|
|
86
|
+
{job.summary && <EntrySummary>{job.summary}</EntrySummary>}
|
|
87
|
+
{renderHighlights(job.highlights)}
|
|
88
|
+
</Entry>
|
|
89
|
+
))}
|
|
90
|
+
</SectionBlock>
|
|
91
|
+
)}
|
|
92
|
+
|
|
93
|
+
{projects?.length > 0 && (
|
|
94
|
+
<SectionBlock>
|
|
95
|
+
<SectionHeading>Projects</SectionHeading>
|
|
96
|
+
{projects.map((project, index) => {
|
|
97
|
+
const summary = project.description || project.summary;
|
|
98
|
+
const descriptor = joinParts(project.entity, project.type);
|
|
99
|
+
return (
|
|
100
|
+
<Entry key={index}>
|
|
101
|
+
<EntryHeader>
|
|
102
|
+
<div>
|
|
103
|
+
{project.name && <EntryTitle>{project.name}</EntryTitle>}
|
|
104
|
+
{(descriptor || project.url) && (
|
|
105
|
+
<EntrySubtitle>
|
|
106
|
+
{descriptor}
|
|
107
|
+
{descriptor && project.url ? ' • ' : ''}
|
|
108
|
+
{project.url && (
|
|
109
|
+
<Anchor href={project.url}>{project.url}</Anchor>
|
|
110
|
+
)}
|
|
111
|
+
</EntrySubtitle>
|
|
112
|
+
)}
|
|
113
|
+
</div>
|
|
114
|
+
{(project.startDate || project.endDate) && (
|
|
115
|
+
<EntryMeta>
|
|
116
|
+
<DateRange
|
|
117
|
+
startDate={project.startDate}
|
|
118
|
+
endDate={project.endDate}
|
|
119
|
+
/>
|
|
120
|
+
</EntryMeta>
|
|
121
|
+
)}
|
|
122
|
+
</EntryHeader>
|
|
123
|
+
{summary && <EntrySummary>{summary}</EntrySummary>}
|
|
124
|
+
{renderHighlights(project.highlights)}
|
|
125
|
+
{project.keywords?.length > 0 && (
|
|
126
|
+
<KeywordList>{project.keywords.join(' • ')}</KeywordList>
|
|
127
|
+
)}
|
|
128
|
+
</Entry>
|
|
129
|
+
);
|
|
130
|
+
})}
|
|
131
|
+
</SectionBlock>
|
|
132
|
+
)}
|
|
133
|
+
|
|
134
|
+
{education?.length > 0 && (
|
|
135
|
+
<SectionBlock>
|
|
136
|
+
<SectionHeading>Education</SectionHeading>
|
|
137
|
+
{education.map((edu, index) => (
|
|
138
|
+
<Entry key={index}>
|
|
139
|
+
<EntryHeader>
|
|
140
|
+
<div>
|
|
141
|
+
{edu.institution && (
|
|
142
|
+
<EntryTitle>{edu.institution}</EntryTitle>
|
|
143
|
+
)}
|
|
144
|
+
{(edu.studyType || edu.area || edu.score) && (
|
|
145
|
+
<EntrySubtitle>
|
|
146
|
+
{joinParts(
|
|
147
|
+
[edu.studyType, edu.area].filter(Boolean).join(' in '),
|
|
148
|
+
edu.score
|
|
149
|
+
)}
|
|
150
|
+
</EntrySubtitle>
|
|
151
|
+
)}
|
|
152
|
+
</div>
|
|
153
|
+
{(edu.startDate || edu.endDate) && (
|
|
154
|
+
<EntryMeta>
|
|
155
|
+
<DateRange
|
|
156
|
+
startDate={edu.startDate}
|
|
157
|
+
endDate={edu.endDate}
|
|
158
|
+
/>
|
|
159
|
+
</EntryMeta>
|
|
160
|
+
)}
|
|
161
|
+
</EntryHeader>
|
|
162
|
+
{edu.courses?.length > 0 && (
|
|
163
|
+
<KeywordList>Key courses: {edu.courses.join(', ')}</KeywordList>
|
|
164
|
+
)}
|
|
165
|
+
</Entry>
|
|
166
|
+
))}
|
|
167
|
+
</SectionBlock>
|
|
168
|
+
)}
|
|
169
|
+
|
|
170
|
+
{skills?.length > 0 && (
|
|
171
|
+
<SectionBlock>
|
|
172
|
+
<SectionHeading>Skills</SectionHeading>
|
|
173
|
+
<SkillGrid>
|
|
174
|
+
{skills.map((skill, index) => (
|
|
175
|
+
<SkillCard key={index}>
|
|
176
|
+
<SkillTitle>
|
|
177
|
+
{skill.name}
|
|
178
|
+
{skill.level && <Pill>{skill.level}</Pill>}
|
|
179
|
+
</SkillTitle>
|
|
180
|
+
{skill.keywords?.length > 0 && (
|
|
181
|
+
<KeywordList>{skill.keywords.join(' • ')}</KeywordList>
|
|
182
|
+
)}
|
|
183
|
+
</SkillCard>
|
|
184
|
+
))}
|
|
185
|
+
</SkillGrid>
|
|
186
|
+
</SectionBlock>
|
|
187
|
+
)}
|
|
188
|
+
|
|
189
|
+
{volunteer?.length > 0 && (
|
|
190
|
+
<SectionBlock>
|
|
191
|
+
<SectionHeading>Volunteer</SectionHeading>
|
|
192
|
+
{volunteer.map((item, index) => (
|
|
193
|
+
<Entry key={index}>
|
|
194
|
+
<EntryHeader>
|
|
195
|
+
<div>
|
|
196
|
+
{item.position && <EntryTitle>{item.position}</EntryTitle>}
|
|
197
|
+
{(item.organization || item.location) && (
|
|
198
|
+
<EntrySubtitle>
|
|
199
|
+
{joinParts(item.organization, item.location)}
|
|
200
|
+
</EntrySubtitle>
|
|
201
|
+
)}
|
|
202
|
+
</div>
|
|
203
|
+
{(item.startDate || item.endDate) && (
|
|
204
|
+
<EntryMeta>
|
|
205
|
+
<DateRange
|
|
206
|
+
startDate={item.startDate}
|
|
207
|
+
endDate={item.endDate}
|
|
208
|
+
/>
|
|
209
|
+
</EntryMeta>
|
|
210
|
+
)}
|
|
211
|
+
</EntryHeader>
|
|
212
|
+
{item.summary && <EntrySummary>{item.summary}</EntrySummary>}
|
|
213
|
+
{renderHighlights(item.highlights)}
|
|
214
|
+
</Entry>
|
|
215
|
+
))}
|
|
216
|
+
</SectionBlock>
|
|
217
|
+
)}
|
|
218
|
+
|
|
219
|
+
{awards?.length > 0 && (
|
|
220
|
+
<SectionBlock>
|
|
221
|
+
<SectionHeading>Awards</SectionHeading>
|
|
222
|
+
{awards.map((award, index) => (
|
|
223
|
+
<Entry key={index}>
|
|
224
|
+
<EntryHeader>
|
|
225
|
+
<div>
|
|
226
|
+
{award.title && <EntryTitle>{award.title}</EntryTitle>}
|
|
227
|
+
{award.awarder && (
|
|
228
|
+
<EntrySubtitle>Issued by {award.awarder}</EntrySubtitle>
|
|
229
|
+
)}
|
|
230
|
+
</div>
|
|
231
|
+
{award.date && <EntryMeta>{award.date}</EntryMeta>}
|
|
232
|
+
</EntryHeader>
|
|
233
|
+
{award.summary && <EntrySummary>{award.summary}</EntrySummary>}
|
|
234
|
+
</Entry>
|
|
235
|
+
))}
|
|
236
|
+
</SectionBlock>
|
|
237
|
+
)}
|
|
238
|
+
|
|
239
|
+
{certificates?.length > 0 && (
|
|
240
|
+
<SectionBlock>
|
|
241
|
+
<SectionHeading>Certifications</SectionHeading>
|
|
242
|
+
{certificates.map((cert, index) => (
|
|
243
|
+
<Entry key={index}>
|
|
244
|
+
<EntryHeader>
|
|
245
|
+
<div>
|
|
246
|
+
{cert.name && <EntryTitle>{cert.name}</EntryTitle>}
|
|
247
|
+
{cert.issuer && (
|
|
248
|
+
<EntrySubtitle>Issued by {cert.issuer}</EntrySubtitle>
|
|
249
|
+
)}
|
|
250
|
+
</div>
|
|
251
|
+
{cert.date && <EntryMeta>{cert.date}</EntryMeta>}
|
|
252
|
+
</EntryHeader>
|
|
253
|
+
{cert.summary && <EntrySummary>{cert.summary}</EntrySummary>}
|
|
254
|
+
{cert.url && (
|
|
255
|
+
<KeywordList>
|
|
256
|
+
<Anchor href={cert.url}>{cert.url}</Anchor>
|
|
257
|
+
</KeywordList>
|
|
258
|
+
)}
|
|
259
|
+
</Entry>
|
|
260
|
+
))}
|
|
261
|
+
</SectionBlock>
|
|
262
|
+
)}
|
|
263
|
+
|
|
264
|
+
{publications?.length > 0 && (
|
|
265
|
+
<SectionBlock>
|
|
266
|
+
<SectionHeading>Publications</SectionHeading>
|
|
267
|
+
{publications.map((pub, index) => (
|
|
268
|
+
<Entry key={index}>
|
|
269
|
+
<EntryHeader>
|
|
270
|
+
<div>
|
|
271
|
+
{pub.name && <EntryTitle>{pub.name}</EntryTitle>}
|
|
272
|
+
{(pub.publisher || pub.url) && (
|
|
273
|
+
<EntrySubtitle>
|
|
274
|
+
{pub.publisher}
|
|
275
|
+
{pub.publisher && pub.url ? ' • ' : ''}
|
|
276
|
+
{pub.url && <Anchor href={pub.url}>{pub.url}</Anchor>}
|
|
277
|
+
</EntrySubtitle>
|
|
278
|
+
)}
|
|
279
|
+
</div>
|
|
280
|
+
{pub.releaseDate && <EntryMeta>{pub.releaseDate}</EntryMeta>}
|
|
281
|
+
</EntryHeader>
|
|
282
|
+
{pub.summary && <EntrySummary>{pub.summary}</EntrySummary>}
|
|
283
|
+
</Entry>
|
|
284
|
+
))}
|
|
285
|
+
</SectionBlock>
|
|
286
|
+
)}
|
|
287
|
+
|
|
288
|
+
{languages?.length > 0 && (
|
|
289
|
+
<SectionBlock>
|
|
290
|
+
<SectionHeading>Languages</SectionHeading>
|
|
291
|
+
<SkillGrid>
|
|
292
|
+
{languages.map((lang, index) => (
|
|
293
|
+
<SkillCard key={index}>
|
|
294
|
+
<SkillTitle>{lang.language}</SkillTitle>
|
|
295
|
+
{lang.fluency && <Pill>{lang.fluency}</Pill>}
|
|
296
|
+
</SkillCard>
|
|
297
|
+
))}
|
|
298
|
+
</SkillGrid>
|
|
299
|
+
</SectionBlock>
|
|
300
|
+
)}
|
|
301
|
+
|
|
302
|
+
{interests?.length > 0 && (
|
|
303
|
+
<SectionBlock>
|
|
304
|
+
<SectionHeading>Interests</SectionHeading>
|
|
305
|
+
<SkillGrid>
|
|
306
|
+
{interests.map((interest, index) => (
|
|
307
|
+
<SkillCard key={index}>
|
|
308
|
+
<SkillTitle>{interest.name}</SkillTitle>
|
|
309
|
+
{interest.keywords?.length > 0 && (
|
|
310
|
+
<KeywordList>{interest.keywords.join(' • ')}</KeywordList>
|
|
311
|
+
)}
|
|
312
|
+
</SkillCard>
|
|
313
|
+
))}
|
|
314
|
+
</SkillGrid>
|
|
315
|
+
</SectionBlock>
|
|
316
|
+
)}
|
|
317
|
+
|
|
318
|
+
{references?.length > 0 && (
|
|
319
|
+
<SectionBlock>
|
|
320
|
+
<SectionHeading>References</SectionHeading>
|
|
321
|
+
{references.map((ref, index) => (
|
|
322
|
+
<Entry key={index}>
|
|
323
|
+
{ref.name && <EntryTitle>{ref.name}</EntryTitle>}
|
|
324
|
+
{ref.reference && <EntrySummary>{ref.reference}</EntrySummary>}
|
|
325
|
+
</Entry>
|
|
326
|
+
))}
|
|
327
|
+
</SectionBlock>
|
|
328
|
+
)}
|
|
329
|
+
</Layout>
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export default Resume;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
22
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
23
|
+
<link href="https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;600;700&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
24
|
+
${styles}
|
|
25
|
+
<style>
|
|
26
|
+
* {
|
|
27
|
+
box-sizing: border-box;
|
|
28
|
+
}
|
|
29
|
+
body {
|
|
30
|
+
margin: 0;
|
|
31
|
+
padding: 0;
|
|
32
|
+
background: #fdf7f2;
|
|
33
|
+
color: #1f2933;
|
|
34
|
+
}
|
|
35
|
+
@media print {
|
|
36
|
+
body {
|
|
37
|
+
background: white;
|
|
38
|
+
}
|
|
39
|
+
@page {
|
|
40
|
+
margin: 0.5in;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
</style>
|
|
44
|
+
</head>
|
|
45
|
+
<body>
|
|
46
|
+
${html}
|
|
47
|
+
</body>
|
|
48
|
+
</html>`;
|
|
49
|
+
} finally {
|
|
50
|
+
sheet.seal();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { Resume };
|
package/src/styles.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
import { Section, SectionTitle, ContactInfo } from '@resume/core';
|
|
3
|
+
|
|
4
|
+
const ACCENT = '#d97706';
|
|
5
|
+
|
|
6
|
+
export const Layout = styled.div`
|
|
7
|
+
max-width: 880px;
|
|
8
|
+
margin: 0 auto;
|
|
9
|
+
padding: 64px 72px;
|
|
10
|
+
background: #fefbf5;
|
|
11
|
+
color: #3f2f25;
|
|
12
|
+
font-family: 'Nunito', 'Inter', 'Segoe UI', sans-serif;
|
|
13
|
+
line-height: 1.7;
|
|
14
|
+
border-radius: 20px;
|
|
15
|
+
box-shadow: 0 32px 60px rgba(149, 108, 57, 0.12);
|
|
16
|
+
border: 1px solid rgba(217, 119, 6, 0.16);
|
|
17
|
+
|
|
18
|
+
@media (max-width: 720px) {
|
|
19
|
+
padding: 48px 28px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@media print {
|
|
23
|
+
padding: 40px 48px;
|
|
24
|
+
border-radius: 0;
|
|
25
|
+
box-shadow: none;
|
|
26
|
+
border: none;
|
|
27
|
+
background: white;
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
export const Header = styled.header`
|
|
32
|
+
display: flex;
|
|
33
|
+
flex-direction: column;
|
|
34
|
+
gap: 16px;
|
|
35
|
+
margin-bottom: 40px;
|
|
36
|
+
padding-bottom: 28px;
|
|
37
|
+
border-bottom: 1px solid rgba(217, 119, 6, 0.25);
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
export const Name = styled.h1`
|
|
41
|
+
font-size: 38px;
|
|
42
|
+
font-weight: 700;
|
|
43
|
+
letter-spacing: 0.02em;
|
|
44
|
+
color: #92400e;
|
|
45
|
+
margin: 0;
|
|
46
|
+
`;
|
|
47
|
+
|
|
48
|
+
export const Label = styled.div`
|
|
49
|
+
font-size: 14px;
|
|
50
|
+
font-weight: 600;
|
|
51
|
+
letter-spacing: 0.28em;
|
|
52
|
+
text-transform: uppercase;
|
|
53
|
+
color: #b45309;
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
export const StyledContactInfo = styled(ContactInfo)`
|
|
57
|
+
display: flex;
|
|
58
|
+
flex-wrap: wrap;
|
|
59
|
+
gap: 12px 24px;
|
|
60
|
+
font-size: 13px;
|
|
61
|
+
color: #6f5d4e;
|
|
62
|
+
|
|
63
|
+
a {
|
|
64
|
+
color: #b45309;
|
|
65
|
+
text-decoration: none;
|
|
66
|
+
border-bottom: 1px solid transparent;
|
|
67
|
+
transition: border-color 0.2s ease;
|
|
68
|
+
|
|
69
|
+
&:hover {
|
|
70
|
+
border-color: rgba(217, 119, 6, 0.5);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
export const Summary = styled.p`
|
|
76
|
+
margin: 0;
|
|
77
|
+
padding: 18px 22px;
|
|
78
|
+
border-radius: 16px;
|
|
79
|
+
background: rgba(255, 255, 255, 0.75);
|
|
80
|
+
border: 1px solid rgba(217, 119, 6, 0.12);
|
|
81
|
+
color: #4f3d31;
|
|
82
|
+
font-size: 15px;
|
|
83
|
+
line-height: 1.8;
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
export const SectionBlock = styled(Section)`
|
|
87
|
+
margin-bottom: 36px;
|
|
88
|
+
padding-top: 24px;
|
|
89
|
+
border-top: 1px solid rgba(217, 119, 6, 0.18);
|
|
90
|
+
|
|
91
|
+
&:last-of-type {
|
|
92
|
+
margin-bottom: 0;
|
|
93
|
+
}
|
|
94
|
+
`;
|
|
95
|
+
|
|
96
|
+
export const SectionHeading = styled(SectionTitle)`
|
|
97
|
+
display: inline-flex;
|
|
98
|
+
align-items: center;
|
|
99
|
+
gap: 12px;
|
|
100
|
+
font-size: 15px;
|
|
101
|
+
font-weight: 700;
|
|
102
|
+
letter-spacing: 0.28em;
|
|
103
|
+
text-transform: uppercase;
|
|
104
|
+
color: #b45309;
|
|
105
|
+
margin: 0 0 20px 0;
|
|
106
|
+
|
|
107
|
+
&::before {
|
|
108
|
+
content: '';
|
|
109
|
+
display: block;
|
|
110
|
+
width: 36px;
|
|
111
|
+
height: 2px;
|
|
112
|
+
background: currentColor;
|
|
113
|
+
opacity: 0.4;
|
|
114
|
+
}
|
|
115
|
+
`;
|
|
116
|
+
|
|
117
|
+
export const Entry = styled.div`
|
|
118
|
+
display: flex;
|
|
119
|
+
flex-direction: column;
|
|
120
|
+
gap: 10px;
|
|
121
|
+
margin-bottom: 24px;
|
|
122
|
+
|
|
123
|
+
&:last-child {
|
|
124
|
+
margin-bottom: 0;
|
|
125
|
+
}
|
|
126
|
+
`;
|
|
127
|
+
|
|
128
|
+
export const EntryHeader = styled.div`
|
|
129
|
+
display: flex;
|
|
130
|
+
justify-content: space-between;
|
|
131
|
+
align-items: flex-start;
|
|
132
|
+
gap: 16px;
|
|
133
|
+
|
|
134
|
+
@media (max-width: 640px) {
|
|
135
|
+
flex-direction: column;
|
|
136
|
+
align-items: flex-start;
|
|
137
|
+
gap: 8px;
|
|
138
|
+
}
|
|
139
|
+
`;
|
|
140
|
+
|
|
141
|
+
export const EntryTitle = styled.h3`
|
|
142
|
+
font-size: 18px;
|
|
143
|
+
font-weight: 600;
|
|
144
|
+
margin: 0;
|
|
145
|
+
color: #4a3326;
|
|
146
|
+
letter-spacing: 0.01em;
|
|
147
|
+
`;
|
|
148
|
+
|
|
149
|
+
export const EntrySubtitle = styled.div`
|
|
150
|
+
font-size: 14px;
|
|
151
|
+
color: #7c6a58;
|
|
152
|
+
`;
|
|
153
|
+
|
|
154
|
+
export const EntryMeta = styled.div`
|
|
155
|
+
font-size: 12px;
|
|
156
|
+
font-weight: 600;
|
|
157
|
+
letter-spacing: 0.12em;
|
|
158
|
+
text-transform: uppercase;
|
|
159
|
+
color: #b45309;
|
|
160
|
+
white-space: nowrap;
|
|
161
|
+
`;
|
|
162
|
+
|
|
163
|
+
export const EntrySummary = styled.p`
|
|
164
|
+
margin: 0;
|
|
165
|
+
color: #4f3d31;
|
|
166
|
+
line-height: 1.75;
|
|
167
|
+
font-size: 14px;
|
|
168
|
+
`;
|
|
169
|
+
|
|
170
|
+
export const BulletList = styled.ul`
|
|
171
|
+
margin: 0;
|
|
172
|
+
padding: 0;
|
|
173
|
+
list-style: none;
|
|
174
|
+
display: grid;
|
|
175
|
+
gap: 8px;
|
|
176
|
+
|
|
177
|
+
li {
|
|
178
|
+
position: relative;
|
|
179
|
+
padding-left: 18px;
|
|
180
|
+
color: #4f3d31;
|
|
181
|
+
font-size: 14px;
|
|
182
|
+
line-height: 1.7;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
li::before {
|
|
186
|
+
content: '';
|
|
187
|
+
position: absolute;
|
|
188
|
+
left: 0;
|
|
189
|
+
top: 10px;
|
|
190
|
+
width: 6px;
|
|
191
|
+
height: 6px;
|
|
192
|
+
border-radius: 50%;
|
|
193
|
+
background: ${ACCENT};
|
|
194
|
+
opacity: 0.6;
|
|
195
|
+
}
|
|
196
|
+
`;
|
|
197
|
+
|
|
198
|
+
export const SkillGrid = styled.div`
|
|
199
|
+
display: grid;
|
|
200
|
+
gap: 18px;
|
|
201
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
202
|
+
`;
|
|
203
|
+
|
|
204
|
+
export const SkillCard = styled.div`
|
|
205
|
+
display: flex;
|
|
206
|
+
flex-direction: column;
|
|
207
|
+
gap: 8px;
|
|
208
|
+
`;
|
|
209
|
+
|
|
210
|
+
export const SkillTitle = styled.div`
|
|
211
|
+
font-size: 15px;
|
|
212
|
+
font-weight: 600;
|
|
213
|
+
color: #4a3326;
|
|
214
|
+
`;
|
|
215
|
+
|
|
216
|
+
export const KeywordList = styled.div`
|
|
217
|
+
font-size: 13px;
|
|
218
|
+
color: #6f5d4e;
|
|
219
|
+
`;
|
|
220
|
+
|
|
221
|
+
export const Pill = styled.span`
|
|
222
|
+
display: inline-flex;
|
|
223
|
+
align-items: center;
|
|
224
|
+
margin-left: 8px;
|
|
225
|
+
padding: 4px 10px;
|
|
226
|
+
border-radius: 999px;
|
|
227
|
+
background: rgba(217, 119, 6, 0.14);
|
|
228
|
+
color: #8a4d0f;
|
|
229
|
+
font-size: 11px;
|
|
230
|
+
font-weight: 600;
|
|
231
|
+
letter-spacing: 0.08em;
|
|
232
|
+
text-transform: uppercase;
|
|
233
|
+
`;
|
|
234
|
+
|
|
235
|
+
export const Anchor = styled.a`
|
|
236
|
+
color: #b45309;
|
|
237
|
+
text-decoration: none;
|
|
238
|
+
border-bottom: 1px solid rgba(217, 119, 6, 0.3);
|
|
239
|
+
transition: border-color 0.2s ease;
|
|
240
|
+
|
|
241
|
+
&:hover {
|
|
242
|
+
border-color: rgba(217, 119, 6, 0.6);
|
|
243
|
+
}
|
|
244
|
+
`;
|