Skip to content

Commit 7459c52

Browse files
committed
feat: add initial HTML template for João Silva's resume
1 parent 9fbcfa3 commit 7459c52

7 files changed

Lines changed: 953 additions & 234 deletions

File tree

backend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"class-transformer": "^0.5.1",
3333
"class-validator": "^0.14.3",
3434
"helmet": "^8.1.0",
35+
"puppeteer": "^24.34.0",
3536
"reflect-metadata": "^0.2.2",
3637
"rxjs": "^7.8.1"
3738
},

backend/pnpm-lock.yaml

Lines changed: 545 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/src/cvs-module/cvs.controller.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Body, Controller, Post } from "@nestjs/common";
1+
import { Body, Controller, Post, Res } from "@nestjs/common";
2+
import type { Response } from "express";
23

34
import { CvsService } from "./cvs.service";
45
import { CreateCvDto } from "./dto/create-cv.dto";
@@ -15,7 +16,16 @@ export class CvsController {
1516
@Post("pdf")
1617
async createCVPdf(
1718
@Body() createCvDto: CreateCvDto,
18-
): Promise<Uint8Array<ArrayBufferLike>> {
19-
return await this.cvsService.createCVPdf(createCvDto);
19+
@Res() res: Response,
20+
): Promise<void> {
21+
const pdfBuffer = await this.cvsService.createCVPdf(createCvDto);
22+
23+
res.set({
24+
"Content-Type": "application/pdf",
25+
"Content-Disposition": `attachment; filename=${createCvDto.cVName}.pdf`,
26+
"Content-Length": pdfBuffer.length,
27+
});
28+
29+
res.end(pdfBuffer);
2030
}
2131
}

backend/src/cvs-module/cvs.service.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,34 @@
11
import { Injectable } from "@nestjs/common";
2+
import puppeteer from "puppeteer";
23
import { cvExample1Template } from "src/templates/examples/example1";
34

45
import { CreateCvDto } from "./dto/create-cv.dto";
56

67
@Injectable()
78
export class CvsService {
89
createCVPreview(createCvDto: CreateCvDto): string {
9-
const htmlPreview = cvExample1Template(createCvDto);
10+
createCvDto.additionalInfo = "";
11+
12+
const htmlPreview = cvExample1Template();
1013

1114
return htmlPreview;
1215
}
1316

1417
async createCVPdf(
1518
createCvDto: CreateCvDto,
1619
): Promise<Uint8Array<ArrayBufferLike>> {
17-
const html = cvExample1Template(createCvDto);
20+
createCvDto.additionalInfo = "";
21+
22+
const html = cvExample1Template();
23+
24+
const browser = await puppeteer.launch();
25+
const page = await browser.newPage();
1826

19-
await new Promise((resolve) => setTimeout(() => resolve(html), 100));
27+
await page.setContent(html, { waitUntil: "networkidle0" });
2028

21-
const pdfBuffer = new Uint8Array(); // Placeholder for PDF generation logic
29+
const pdfBuffer = await page.pdf({ format: "A4", printBackground: true });
2230

23-
// PDF generation logic would go here, using a library like Puppeteer or PDFKit
31+
await browser.close();
2432

2533
return pdfBuffer;
2634
}
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
<!DOCTYPE html>
2+
<html lang="pt-BR">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>Currículo - João Silva</title>
6+
7+
<style>
8+
* {
9+
margin: 0;
10+
padding: 0;
11+
box-sizing: border-box;
12+
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
13+
}
14+
15+
body {
16+
background: #f4f6f8;
17+
padding: 40px;
18+
}
19+
20+
.container {
21+
max-width: 800px;
22+
margin: auto;
23+
background: #ffffff;
24+
padding: 40px;
25+
border-radius: 8px;
26+
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
27+
}
28+
29+
header {
30+
display: flex;
31+
justify-content: space-between;
32+
align-items: center;
33+
border-bottom: 2px solid #eaeaea;
34+
padding-bottom: 20px;
35+
margin-bottom: 30px;
36+
}
37+
38+
header h1 {
39+
font-size: 32px;
40+
color: #2c3e50;
41+
}
42+
43+
header h2 {
44+
font-size: 18px;
45+
font-weight: normal;
46+
color: #7f8c8d;
47+
margin-top: 4px;
48+
}
49+
50+
.contact {
51+
text-align: right;
52+
font-size: 14px;
53+
color: #555;
54+
}
55+
56+
.contact p {
57+
margin-bottom: 4px;
58+
}
59+
60+
section {
61+
margin-bottom: 30px;
62+
}
63+
64+
section h3 {
65+
font-size: 20px;
66+
color: #34495e;
67+
margin-bottom: 12px;
68+
border-left: 4px solid #3498db;
69+
padding-left: 10px;
70+
}
71+
72+
.about {
73+
font-size: 15px;
74+
line-height: 1.6;
75+
color: #444;
76+
}
77+
78+
.experience,
79+
.education {
80+
margin-bottom: 15px;
81+
}
82+
83+
.item-title {
84+
font-weight: bold;
85+
font-size: 16px;
86+
color: #2c3e50;
87+
}
88+
89+
.item-subtitle {
90+
font-size: 14px;
91+
color: #7f8c8d;
92+
margin-bottom: 6px;
93+
}
94+
95+
.item-description {
96+
font-size: 14px;
97+
color: #444;
98+
line-height: 1.5;
99+
}
100+
101+
ul.skills {
102+
display: flex;
103+
flex-wrap: wrap;
104+
gap: 10px;
105+
list-style: none;
106+
}
107+
108+
ul.skills li {
109+
background: #3498db;
110+
color: white;
111+
padding: 6px 12px;
112+
border-radius: 20px;
113+
font-size: 13px;
114+
}
115+
116+
footer {
117+
text-align: center;
118+
font-size: 12px;
119+
color: #999;
120+
margin-top: 40px;
121+
}
122+
123+
@media print {
124+
body {
125+
background: none;
126+
padding: 0;
127+
}
128+
129+
.container {
130+
box-shadow: none;
131+
border-radius: 0;
132+
}
133+
}
134+
</style>
135+
</head>
136+
137+
<body>
138+
<div class="container">
139+
140+
<header>
141+
<div>
142+
<h1>João Silva</h1>
143+
<h2>Desenvolvedor Full Stack</h2>
144+
</div>
145+
146+
<div class="contact">
147+
<p>📧 joao@email.com</p>
148+
<p>📱 (11) 99999-9999</p>
149+
<p>🌐 github.com/joaosilva</p>
150+
<p>📍 São Paulo - SP</p>
151+
</div>
152+
</header>
153+
154+
<section>
155+
<h3>Perfil Profissional</h3>
156+
<p class="about">
157+
Desenvolvedor Full Stack com experiência em criação de aplicações web modernas,
158+
APIs REST e sistemas escaláveis. Focado em performance, código limpo e boas práticas.
159+
</p>
160+
</section>
161+
162+
<section>
163+
<h3>Experiência Profissional</h3>
164+
165+
<div class="experience">
166+
<p class="item-title">Desenvolvedor Full Stack</p>
167+
<p class="item-subtitle">Empresa XYZ • 2022 - Atual</p>
168+
<p class="item-description">
169+
Desenvolvimento de aplicações em React e Node.js, integração com APIs,
170+
banco de dados SQL/NoSQL e implementação de autenticação e segurança.
171+
</p>
172+
</div>
173+
174+
<div class="experience">
175+
<p class="item-title">Desenvolvedor Front-end</p>
176+
<p class="item-subtitle">Empresa ABC • 2020 - 2022</p>
177+
<p class="item-description">
178+
Criação de interfaces responsivas, otimização de performance
179+
e colaboração com designers e back-end.
180+
</p>
181+
</div>
182+
</section>
183+
184+
<section>
185+
<h3>Formação Acadêmica</h3>
186+
187+
<div class="education">
188+
<p class="item-title">Bacharel em Ciência da Computação</p>
189+
<p class="item-subtitle">Universidade Exemplo • 2016 - 2020</p>
190+
</div>
191+
</section>
192+
193+
<section>
194+
<h3>Habilidades Técnicas</h3>
195+
<ul class="skills">
196+
<li>JavaScript</li>
197+
<li>TypeScript</li>
198+
<li>React</li>
199+
<li>Node.js</li>
200+
<li>HTML</li>
201+
<li>CSS</li>
202+
<li>SQL</li>
203+
<li>Git</li>
204+
<li>Docker</li>
205+
</ul>
206+
</section>
207+
208+
<footer>
209+
Currículo gerado automaticamente via Node.js
210+
</footer>
211+
212+
</div>
213+
</body>
214+
</html>

0 commit comments

Comments
 (0)