Persano commited on
Commit
cddb3f3
·
verified ·
1 Parent(s): a4c7e98

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +326 -151
templates/index.html CHANGED
@@ -1,171 +1,346 @@
1
  <!DOCTYPE html>
2
  <html lang="pt-BR">
3
  <head>
4
- <meta charset="UTF-8" />
5
- <title>Simulador de Investimentos</title>
6
- <style>
7
- body {
8
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
9
- background: #f8fafc;
10
- padding: 40px;
11
- display: flex;
12
- flex-direction: column;
13
- align-items: center;
14
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
- .card {
17
- background: #fff;
18
- padding: 30px;
19
- border-radius: 12px;
20
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
21
- max-width: 700px;
22
- width: 100%;
23
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
- h1 {
26
- color: #111827;
27
- font-size: 26px;
28
- margin-bottom: 20px;
29
- text-align: center;
30
- }
 
 
 
 
 
 
 
 
 
 
 
31
 
32
- form {
33
- display: flex;
34
- flex-wrap: wrap;
35
- gap: 15px;
36
- justify-content: space-between;
37
  }
 
 
 
 
 
 
 
 
 
 
38
 
39
- label {
40
- font-weight: 600;
41
- color: #374151;
42
- flex-basis: 100%;
43
- }
 
44
 
45
- .input-group {
46
- display: flex;
47
- flex-direction: column;
48
- flex-basis: 48%;
49
- }
50
 
51
- input {
52
- padding: 10px;
53
- border: 1px solid #d1d5db;
54
- border-radius: 8px;
55
- font-size: 16px;
56
- }
57
 
58
- button {
59
- background: #2563eb;
60
- color: white;
61
- padding: 12px;
62
- font-size: 16px;
63
- border: none;
64
- border-radius: 8px;
65
- cursor: pointer;
66
- transition: background 0.3s ease;
67
- margin-top: 10px;
68
- flex-basis: 100%;
69
- }
70
 
71
- button:hover {
72
- background: #1d4ed8;
73
- }
 
 
74
 
75
- .grafico {
76
- margin-top: 30px;
77
- text-align: center;
78
- }
 
79
 
80
- table {
81
- margin-top: 30px;
82
- width: 100%;
83
- border-collapse: collapse;
84
- font-size: 15px;
85
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
- th, td {
88
- border: 1px solid #e5e7eb;
89
- padding: 8px 12px;
90
- text-align: center;
 
 
 
 
 
 
 
91
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
- th {
94
- background: #f3f4f6;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  }
96
- </style>
97
- </head>
98
- <body>
99
- <div class="card">
100
- <h1>Simulador de Comparação de Investimentos</h1>
101
- <form method="post">
102
- <div class="input-group">
103
- <label for="capital">Capital Inicial (R$):</label>
104
- <input type="number" name="capital" id="capital" step="100" required value="{{ params.capital }}">
105
- </div>
106
-
107
- <div class="input-group">
108
- <label for="studio_valor_anual">Receita anual líquida do Studio (R$):</label>
109
- <input type="number" name="studio_valor_anual" id="studio_valor_anual" step="100" required value="{{ params.studio_valor_anual }}">
110
- </div>
111
-
112
- <div class="input-group">
113
- <label for="studio_valoriza">Taxa de valorização do Studio (% a.a.):</label>
114
- <input type="number" name="studio_valoriza" id="studio_valoriza" step="0.1" required value="{{ params.studio_valoriza }}">
115
- </div>
116
-
117
- <div class="input-group">
118
- <label for="franquia_valor_anual">Receita anual da Franquia (R$):</label>
119
- <input type="number" name="franquia_valor_anual" id="franquia_valor_anual" step="100" required value="{{ params.franquia_valor_anual }}">
120
- </div>
121
-
122
- <div class="input-group">
123
- <label for="acoes_retorno">Rentabilidade anual das Ações (%):</label>
124
- <input type="number" name="acoes_retorno" id="acoes_retorno" step="0.1" required value="{{ params.acoes_retorno }}">
125
- </div>
126
-
127
- <div class="input-group">
128
- <label for="renda_fixa_retorno">Rentabilidade anual da Renda Fixa (%):</label>
129
- <input type="number" name="renda_fixa_retorno" id="renda_fixa_retorno" step="0.1" required value="{{ params.renda_fixa_retorno }}">
130
- </div>
131
-
132
- <button type="submit">Simular</button>
133
- </form>
134
-
135
- {% if grafico %}
136
- <div class="grafico">
137
- <h2>Resultado da Simulação</h2>
138
- <img src="data:image/png;base64,{{ grafico }}" alt="Gráfico de Simulação">
139
- </div>
140
-
141
- <form action="/download_csv" method="post">
142
- {% for key, value in params.items() %}
143
- <input type="hidden" name="{{ key }}" value="{{ value }}">
144
- {% endfor %}
145
- <button type="submit" style="margin-top: 15px;">📥 Baixar CSV</button>
146
- </form>
147
-
148
- <table>
149
- <thead>
150
- <tr>
151
- <th>Ano</th>
152
- {% for tipo in resultados %}
153
- <th>{{ tipo.title() }}</th>
154
- {% endfor %}
155
- </tr>
156
- </thead>
157
- <tbody>
158
- {% for i in range(anos|length) %}
159
- <tr>
160
- <td>{{ anos[i] }}</td>
161
- {% for tipo in resultados %}
162
- <td>R$ {{ '%.2f'|format(resultados[tipo][i]) }}</td>
163
- {% endfor %}
164
- </tr>
165
- {% endfor %}
166
- </tbody>
167
- </table>
168
- {% endif %}
169
- </div>
170
  </body>
171
  </html>
 
1
  <!DOCTYPE html>
2
  <html lang="pt-BR">
3
  <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Comparador de Investimentos</title>
7
+ <link
8
+ href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
9
+ rel="stylesheet"
10
+ />
11
+ <style>
12
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap');
13
+ :root {
14
+ --clr-bg-light: #f9fafb;
15
+ --clr-text-light: #222;
16
+ --clr-bg-dark: #121212;
17
+ --clr-text-dark: #eee;
18
+ --clr-primary: #00c9a7;
19
+ --clr-secondary: #007cf0;
20
+ }
21
+ body {
22
+ font-family: 'Inter', sans-serif;
23
+ margin: 0;
24
+ padding: 0;
25
+ min-height: 100vh;
26
+ background: var(--clr-bg-dark);
27
+ color: var(--clr-text-dark);
28
+ transition: background 0.3s, color 0.3s;
29
+ display: flex;
30
+ flex-direction: column;
31
+ align-items: center;
32
+ justify-content: start;
33
+ overflow-x: hidden;
34
+ }
35
+ body.light {
36
+ background: var(--clr-bg-light);
37
+ color: var(--clr-text-light);
38
+ }
39
+ header {
40
+ width: 100%;
41
+ max-width: 960px;
42
+ margin: 32px 16px 12px;
43
+ display: flex;
44
+ justify-content: space-between;
45
+ align-items: center;
46
+ }
47
+ h1 {
48
+ font-size: 2.8rem;
49
+ background: linear-gradient(to right, var(--clr-primary), var(--clr-secondary));
50
+ -webkit-background-clip: text;
51
+ -webkit-text-fill-color: transparent;
52
+ margin: 0;
53
+ user-select: none;
54
+ }
55
+ button#toggleTheme {
56
+ cursor: pointer;
57
+ font-size: 1.6rem;
58
+ background: none;
59
+ border: none;
60
+ color: var(--clr-primary);
61
+ transition: color 0.3s ease;
62
+ }
63
+ button#toggleTheme:hover {
64
+ color: var(--clr-secondary);
65
+ }
66
+ form {
67
+ background: var(--clr-bg-dark);
68
+ padding: 40px 48px;
69
+ border-radius: 20px;
70
+ box-shadow: 0 4px 25px rgba(0,0,0,0.65);
71
+ max-width: 640px;
72
+ width: 100%;
73
+ margin-bottom: 48px;
74
+ transition: background 0.3s;
75
+ }
76
+ body.light form {
77
+ background: var(--clr-bg-light);
78
+ box-shadow: 0 4px 20px rgba(0,0,0,0.1);
79
+ }
80
+ .form-group {
81
+ margin-bottom: 24px;
82
+ position: relative;
83
+ }
84
+ label {
85
+ font-weight: 600;
86
+ display: block;
87
+ margin-bottom: 6px;
88
+ }
89
+ input[type=number], select {
90
+ width: 100%;
91
+ padding: 12px 44px 12px 16px;
92
+ font-size: 1rem;
93
+ border-radius: 10px;
94
+ border: 1px solid #333;
95
+ background-color: var(--clr-bg-dark);
96
+ color: var(--clr-text-dark);
97
+ transition: background-color 0.3s, color 0.3s, border-color 0.3s;
98
+ }
99
+ body.light input[type=number], body.light select {
100
+ background-color: var(--clr-bg-light);
101
+ color: var(--clr-text-light);
102
+ border-color: #ccc;
103
+ }
104
+ input[type=number]:focus, select:focus {
105
+ outline: none;
106
+ border-color: var(--clr-primary);
107
+ box-shadow: 0 0 5px var(--clr-primary);
108
+ }
109
+ .icon-input {
110
+ position: absolute;
111
+ right: 16px;
112
+ top: 38px;
113
+ font-size: 1.3rem;
114
+ color: var(--clr-primary);
115
+ pointer-events: none;
116
+ }
117
+ button[type=submit] {
118
+ width: 100%;
119
+ background: linear-gradient(135deg, var(--clr-primary), var(--clr-secondary));
120
+ border: none;
121
+ border-radius: 14px;
122
+ color: white;
123
+ font-size: 1.2rem;
124
+ font-weight: 700;
125
+ padding: 16px 0;
126
+ cursor: pointer;
127
+ transition: transform 0.25s ease, box-shadow 0.25s ease;
128
+ }
129
+ button[type=submit]:hover {
130
+ transform: translateY(-3px);
131
+ box-shadow: 0 12px 30px rgba(0,201,167,0.5);
132
+ }
133
 
134
+ /* Drawer sidebar */
135
+ #drawer {
136
+ position: fixed;
137
+ top: 0;
138
+ right: -400px;
139
+ width: 400px;
140
+ max-width: 90vw;
141
+ height: 100vh;
142
+ background: var(--clr-bg-dark);
143
+ box-shadow: -4px 0 24px rgba(0,0,0,0.7);
144
+ transition: right 0.35s ease;
145
+ overflow-y: auto;
146
+ padding: 24px 28px 48px;
147
+ z-index: 1001;
148
+ }
149
+ body.light #drawer {
150
+ background: var(--clr-bg-light);
151
+ box-shadow: -4px 0 24px rgba(0,0,0,0.15);
152
+ }
153
+ #drawer.open {
154
+ right: 0;
155
+ }
156
+ #drawer h2 {
157
+ color: var(--clr-primary);
158
+ font-weight: 700;
159
+ margin-top: 0;
160
+ margin-bottom: 20px;
161
+ }
162
+ #drawer p {
163
+ line-height: 1.5;
164
+ margin-bottom: 16px;
165
+ color: inherit;
166
+ }
167
+ #drawer img {
168
+ max-width: 100%;
169
+ border-radius: 14px;
170
+ box-shadow: 0 0 16px rgba(0,0,0,0.35);
171
+ margin-bottom: 28px;
172
+ }
173
+ #drawerCloseBtn {
174
+ position: absolute;
175
+ top: 18px;
176
+ right: 18px;
177
+ background: transparent;
178
+ border: none;
179
+ font-size: 1.8rem;
180
+ cursor: pointer;
181
+ color: var(--clr-primary);
182
+ transition: color 0.3s;
183
+ }
184
+ #drawerCloseBtn:hover {
185
+ color: var(--clr-secondary);
186
+ }
187
 
188
+ /* Overlay behind drawer */
189
+ #drawerOverlay {
190
+ position: fixed;
191
+ top: 0;
192
+ left: 0;
193
+ width: 100vw;
194
+ height: 100vh;
195
+ background: rgba(0,0,0,0.5);
196
+ opacity: 0;
197
+ pointer-events: none;
198
+ transition: opacity 0.3s ease;
199
+ z-index: 1000;
200
+ }
201
+ #drawerOverlay.open {
202
+ opacity: 1;
203
+ pointer-events: all;
204
+ }
205
 
206
+ @media (max-width: 700px) {
207
+ #drawer {
208
+ width: 100vw;
 
 
209
  }
210
+ }
211
+ </style>
212
+ </head>
213
+ <body>
214
+ <header>
215
+ <h1>Comparador de Investimentos</h1>
216
+ <button id="toggleTheme" aria-label="Alternar tema claro/escuro">
217
+ <i class="fa-regular fa-sun"></i>
218
+ </button>
219
+ </header>
220
 
221
+ <form method="POST" id="formSimulador">
222
+ <div class="form-group">
223
+ <label for="capital">Capital Inicial (R$)</label>
224
+ <input type="number" name="capital" id="capital" step="1000" min="10000" placeholder="Ex: 400000" required />
225
+ <i class="fa-solid fa-wallet icon-input"></i>
226
+ </div>
227
 
228
+ <div class="form-group">
229
+ <label for="studio_ret">Retorno mensal do Studio (%)</label>
230
+ <input type="number" name="studio_ret" id="studio_ret" step="0.1" min="0" max="5" placeholder="Ex: 1.0" required />
231
+ <i class="fa-solid fa-building icon-input"></i>
232
+ </div>
233
 
234
+ <div class="form-group">
235
+ <label for="valorizacao">Valorização anual do imóvel (%)</label>
236
+ <input type="number" name="valorizacao" id="valorizacao" step="0.1" min="0" max="20" placeholder="Ex: 6.0" required />
237
+ <i class="fa-solid fa-chart-line icon-input"></i>
238
+ </div>
 
239
 
240
+ <div class="form-group">
241
+ <label for="franquia_ret">Lucro anual da Franquia (R$)</label>
242
+ <input type="number" name="franquia_ret" id="franquia_ret" step="1000" min="0" placeholder="Ex: 20000" required />
243
+ <i class="fa-solid fa-shop icon-input"></i>
244
+ </div>
 
 
 
 
 
 
 
245
 
246
+ <div class="form-group">
247
+ <label for="acoes_ret">Retorno anual em Ações (%)</label>
248
+ <input type="number" name="acoes_ret" id="acoes_ret" step="0.1" min="0" max="50" placeholder="Ex: 10.0" required />
249
+ <i class="fa-solid fa-chart-pie icon-input"></i>
250
+ </div>
251
 
252
+ <div class="form-group">
253
+ <label for="renda_fixa">Retorno anual Renda Fixa (%)</label>
254
+ <input type="number" name="renda_fixa" id="renda_fixa" step="0.1" min="0" max="30" placeholder="Ex: 9.0" required />
255
+ <i class="fa-solid fa-coins icon-input"></i>
256
+ </div>
257
 
258
+ <div class="form-group">
259
+ <label for="inflacao">Inflação anual média esperada (%)</label>
260
+ <input type="number" name="inflacao" id="inflacao" step="0.1" min="0" max="15" placeholder="Ex: 4.5" required />
261
+ <i class="fa-solid fa-percent icon-input"></i>
262
+ </div>
263
+
264
+ <button type="submit">📊 Simular Retorno</button>
265
+ </form>
266
+
267
+ <!-- Drawer Sidebar -->
268
+ <div id="drawer" aria-hidden="true" role="complementary" aria-label="Detalhes da Simulação">
269
+ <button id="drawerCloseBtn" aria-label="Fechar painel de resultados">&times;</button>
270
+ <h2>📈 Resultado da Simulação</h2>
271
+ <div id="resultadoTexto">
272
+ <!-- Conteúdo será injetado aqui -->
273
+ </div>
274
+ <div id="resultadoGrafico">
275
+ <!-- Imagem do gráfico será injetada aqui -->
276
+ </div>
277
+ </div>
278
 
279
+ <div id="drawerOverlay"></div>
280
+
281
+ <script>
282
+ const toggleThemeBtn = document.getElementById('toggleTheme');
283
+ const body = document.body;
284
+
285
+ function updateThemeIcon() {
286
+ if (body.classList.contains('light')) {
287
+ toggleThemeBtn.innerHTML = '<i class="fa-regular fa-moon"></i>';
288
+ } else {
289
+ toggleThemeBtn.innerHTML = '<i class="fa-regular fa-sun"></i>';
290
  }
291
+ }
292
+
293
+ toggleThemeBtn.addEventListener('click', () => {
294
+ body.classList.toggle('light');
295
+ updateThemeIcon();
296
+ });
297
+ updateThemeIcon();
298
+
299
+ // Drawer functionality
300
+ const drawer = document.getElementById('drawer');
301
+ const drawerOverlay = document.getElementById('drawerOverlay');
302
+ const drawerCloseBtn = document.getElementById('drawerCloseBtn');
303
+ const form = document.getElementById('formSimulador');
304
+ const resultadoTexto = document.getElementById('resultadoTexto');
305
+ const resultadoGrafico = document.getElementById('resultadoGrafico');
306
 
307
+ function openDrawer() {
308
+ drawer.classList.add('open');
309
+ drawerOverlay.classList.add('open');
310
+ drawer.setAttribute('aria-hidden', 'false');
311
+ }
312
+ function closeDrawer() {
313
+ drawer.classList.remove('open');
314
+ drawerOverlay.classList.remove('open');
315
+ drawer.setAttribute('aria-hidden', 'true');
316
+ }
317
+
318
+ drawerCloseBtn.addEventListener('click', closeDrawer);
319
+ drawerOverlay.addEventListener('click', closeDrawer);
320
+
321
+ form.addEventListener('submit', async (e) => {
322
+ e.preventDefault();
323
+
324
+ const formData = new FormData(form);
325
+ // Enviar dados para backend via fetch POST e receber resultado JSON
326
+ // Supondo que exista um endpoint /simular que retorna { texto: "...", graficoBase64: "..." }
327
+ try {
328
+ const response = await fetch('/simular', {
329
+ method: 'POST',
330
+ body: formData,
331
+ });
332
+ if (!response.ok) throw new Error('Erro na simulação');
333
+ const data = await response.json();
334
+
335
+ resultadoTexto.innerHTML = `<p>${data.texto.replace(/\n/g, '<br>')}</p>`;
336
+ resultadoGrafico.innerHTML = `<img src="data:image/png;base64,${data.graficoBase64}" alt="Gráfico da simulação" />`;
337
+
338
+ openDrawer();
339
+ } catch (err) {
340
+ alert('Erro ao obter resultado da simulação. Tente novamente.');
341
+ console.error(err);
342
  }
343
+ });
344
+ </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
  </body>
346
  </html>