api: fix icons on glide animation, add logo, drop giant square img
Parents:
a929bda3 file(s) changed
- api/src/static/index.html +8 -10
- api/src/static/js/app.js +6 -52
- api/src/static/styles/main.css +8 -0
api/src/static/index.html
1 1
<!DOCTYPE html>
2 2
<html class="light" lang="pt-BR">
3 3
<head>
4 4
<meta charset="utf-8"/>
5 5
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
▸ 63 unchanged lines
69 69
</head>
70 70
71 71
<body class="text-text-primary">
72 72
<header class="docked full-width top-0 sticky z-50 bg-surface-light/95 backdrop-blur-md border-b border-border-subtle shadow-sm">
73 73
<nav class="flex justify-between items-center w-full px-container-padding max-w-7xl mx-auto h-16">
74 -
<div class="text-headline-lg font-headline-lg text-text-primary">nexo</div>
74 +
<div class="flex items-center gap-2">
75 +
<img src="/images/logo.svg" alt="" class="w-6 h-6 spin-slow" />
76 +
<span class="text-headline-lg font-headline-lg text-text-primary">nexo</span>
77 +
</div>
75 78
<div class="hidden md:flex gap-8">
76 79
<a class="text-text-primary font-bold border-b-2 border-status-active-bg transition-colors duration-200" href="#">
77 80
Funcionalidades
78 81
</a>
79 82
▸ 36 unchanged lines
116 119
</div>
117 120
</div>
118 121
119 122
<div class="flex-1 relative flex items-center justify-center">
120 123
<div class="absolute -top-12 -left-12 w-64 h-64 bg-brand-green/10 rounded-full blur-3xl animate-pulse"></div>
121 -
<div id="logo-container" class="relative z-10 w-64 h-64 md:w-80 md:h-80 cursor-pointer select-none">
122 -
<img id="logo-img" alt="nexo" src="/images/logo.svg" class="w-full h-full" />
123 -
</div>
124 +
<div id="logo-container" class="relative z-10 w-64 h-64 md:w-80 md:h-80 cursor-pointer select-none"></div>
124 125
</div>
125 126
</section>
126 127
127 128
<section class="bg-surface-light py-20 border-y border-border-subtle">
128 129
<div class="max-w-7xl mx-auto px-container-padding">
▸ 10 unchanged lines
139 140
<div class="bg-background-light p-8 rounded-xl border border-border-subtle h-full group hover:shadow-md transition-shadow">
140 141
<div class="w-12 h-12 bg-pill-indigo rounded-lg flex items-center justify-center mb-6">
141 142
<svg class="w-6 h-6 text-indigo-600 morph-icon" viewBox="0 0 24 24" fill="currentColor">
142 143
<defs>
143 144
<path class="morph-resting" d="M12 3 L13 10 L20 8 L14 12 L20 16 L13 14 L12 21 L11 14 L4 16 L10 12 L4 8 L11 10 Z"/>
144 -
<path class="morph-alt" d="M12 1 L13 10 L22 7 L14 12 L22 17 L13 14 L12 23 L11 14 L2 17 L10 12 L2 7 L11 10 Z"/>
145 -
<path class="morph-shape" d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5zm-7 0c.83 0 1.5-.67 1.5-1.5S9.33 8 8.5 8 7 8.67 7 9.5 7.67 11 8.5 11zm3.5 6.5c2.33 0 4.31-1.46 5.11-3.5H6.89c.8 2.04 2.78 3.5 5.11 3.5z"/>
145 +
<path class="morph-shape" d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
146 146
</defs>
147 147
<path d="M12 3 L13 10 L20 8 L14 12 L20 16 L13 14 L12 21 L11 14 L4 16 L10 12 L4 8 L11 10 Z"/>
148 148
</svg>
149 149
</div>
150 150
<h3 class="font-headline-md text-xl mb-3">Monitoramento de Humor</h3>
▸ 12 unchanged lines
163 163
<div class="bg-background-light p-8 rounded-xl border border-border-subtle h-full group hover:shadow-md transition-shadow">
164 164
<div class="w-12 h-12 bg-pill-purple rounded-lg flex items-center justify-center mb-6">
165 165
<svg class="w-6 h-6 text-purple-600 morph-icon" viewBox="0 0 24 24" fill="currentColor">
166 166
<defs>
167 167
<path class="morph-resting" d="M12 3 L13 10 L20 8 L14 12 L20 16 L13 14 L12 21 L11 14 L4 16 L10 12 L4 8 L11 10 Z"/>
168 -
<path class="morph-alt" d="M12 2 L15 8 L21 7 L17 12 L21 17 L15 16 L12 22 L9 16 L3 17 L7 12 L3 7 L9 8 Z"/>
169 -
<path class="morph-shape" d="M20 6h-4V4c0-1.1-.9-2-2-2h-4c-1.1 0-2 .9-2 2v2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zM10 4h4v2h-4V4zm10 16H4V8h16v12z M13 10h-2v3H8v2h3v3h2v-3h3v-2h-3z"/>
168 +
<path class="morph-shape" d="M17 11h-4V7h-2v4H7v2h4v4h2v-4h4z"/>
170 169
</defs>
171 170
<path d="M12 3 L13 10 L20 8 L14 12 L20 16 L13 14 L12 21 L11 14 L4 16 L10 12 L4 8 L11 10 Z"/>
172 171
</svg>
173 172
</div>
174 173
<h3 class="font-headline-md text-xl mb-3">Gestão de Saúde</h3>
▸ 10 unchanged lines
185 184
<div class="bg-background-light p-8 rounded-xl border border-border-subtle h-full group hover:shadow-md transition-shadow">
186 185
<div class="w-12 h-12 bg-pill-blue rounded-lg flex items-center justify-center mb-6">
187 186
<svg class="w-6 h-6 text-blue-600 morph-icon" viewBox="0 0 24 24" fill="currentColor">
188 187
<defs>
189 188
<path class="morph-resting" d="M12 3 L13 10 L20 8 L14 12 L20 16 L13 14 L12 21 L11 14 L4 16 L10 12 L4 8 L11 10 Z"/>
190 -
<path class="morph-alt" d="M17 4 L14 11 L21 12 L14 13 L17 20 L12 14 L7 20 L10 13 L3 12 L10 11 L7 4 L12 10 Z"/>
191 -
<path class="morph-shape" d="M9.27 4.49c-1.63 7.54 3.75 12.41 7.66 13.8A7.993 7.993 0 0 1 12 20c-4.41 0-8-3.59-8-8 0-3.45 2.2-6.4 5.27-7.51m2.72-2.48C6.4 2.01 2 6.54 2 12c0 5.52 4.48 10 10 10 3.71 0 6.93-2.02 8.66-5.02-7.51-.25-12.09-8.43-8.32-14.97h-.35z"/>
189 +
<path class="morph-shape" d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9 9-4.03 9-9c0-.46-.04-.92-.1-1.36-.98 1.37-2.58 2.26-4.4 2.26-2.98 0-5.4-2.42-5.4-5.4 0-1.81.89-3.42 2.26-4.4-.44-.06-.9-.1-1.36-.1z"/>
192 190
</defs>
193 191
<path d="M12 3 L13 10 L20 8 L14 12 L20 16 L13 14 L12 21 L11 14 L4 16 L10 12 L4 8 L11 10 Z"/>
194 192
</svg>
195 193
</div>
196 194
▸ 204 unchanged lines
401 399
<script src="https://cdn.jsdelivr.net/npm/atropos/atropos.min.js"></script>
402 400
<script src="/js/app.js">
403 401
</script>
404 402
</body>
405 403
</html>
api/src/static/js/app.js
1 1
const { animate, utils, stagger, splitText, morphTo } = anime;
2 2
3 3
// Motion path: glowing dot traces the logo outline.
4 4
// morphTo on hover: logo → 16-pt star, tries to mimic the logo
5 5
▸ 103 unchanged lines
109 109
});
110 110
111 111
svg.appendChild(trail);
112 112
svg.appendChild(dot);
113 113
114 -
const img = container.querySelector('img');
115 -
if (img) container.replaceChild(svg, img);
116 -
else container.appendChild(svg);
114 +
container.appendChild(svg);
117 115
118 116
// Motion path
119 117
const totalLen = logoPathEl.getTotalLength();
120 118
if (!totalLen) return;
121 119
▸ 86 unchanged lines
208 206
});
209 207
210 208
setupLogoAnimations();
211 209
212 210
document.querySelectorAll('.glide__slide .morph-icon').forEach(svg => {
213 -
const path = svg.querySelector(':scope > path');
211 +
const path = svg.querySelector(':scope > path');
214 212
const resting = svg.querySelector('defs .morph-resting');
215 -
const alt = svg.querySelector('defs .morph-alt');
216 -
const shape = svg.querySelector('defs .morph-shape');
217 -
const card = svg.closest('.group');
218 -
219 -
let hovered = false;
220 -
let spikeCycle = null;
221 -
222 -
const rotAnim = animate(svg, {
223 -
rotate: 360,
224 -
loop: true,
225 -
duration: 7000,
226 -
ease: 'linear',
227 -
});
228 -
229 -
function runSpikeCycle() {
230 -
if (hovered) return;
231 -
const targets = [resting, alt];
232 -
let i = 0;
233 -
234 -
function step() {
235 -
if (hovered) return;
236 -
i = (i + 1) % targets.length;
237 -
spikeCycle = animate(path, {
238 -
d: morphTo(targets[i]),
239 -
duration: 1800,
240 -
ease: 'inOutSine',
241 -
onComplete: () => setTimeout(step, 600),
242 -
});
243 -
}
244 -
step();
245 -
}
246 -
247 -
runSpikeCycle();
213 +
const shape = svg.querySelector('defs .morph-shape');
214 +
const card = svg.closest('.group');
248 215
249 216
card.addEventListener('pointerenter', () => {
250 -
hovered = true;
251 -
spikeCycle?.pause();
252 -
rotAnim.pause();
253 -
animate(path, { d: morphTo(shape), duration: 500, ease: 'inOutCubic' });
217 +
animate(path, { d: morphTo(shape), duration: 500, ease: 'inOutCubic' });
254 218
});
255 -
256 219
card.addEventListener('pointerleave', () => {
257 -
hovered = false;
258 -
animate(path, {
259 -
d: morphTo(resting),
260 -
duration: 500,
261 -
ease: 'inOutCubic',
262 -
onComplete: () => {
263 -
rotAnim.play();
264 -
runSpikeCycle();
265 -
},
266 -
});
220 +
animate(path, { d: morphTo(resting), duration: 500, ease: 'inOutCubic' });
267 221
});
268 222
});
269 223
});
api/src/static/styles/main.css
1 1
body {
2 2
font-family: 'Inter', sans-serif; background-color: #f6f8f6;
3 3
}
4 4
5 5
.material-symbols-outlined {
▸ 10 unchanged lines
16 16
17 17
.morph-icon {
18 18
transform-origin: center;
19 19
}
20 20
21 +
@keyframes spin-slow {
22 +
to { transform: rotate(360deg); }
23 +
}
24 +
25 +
.spin-slow {
26 +
animation: spin-slow 12s linear infinite;
27 +
}
28 +
21 29
.btn-hover-effect {
22 30
transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
23 31
}
24 32
25 33
.btn-hover-effect:active {
26 34
transform: scale(0.95);
27 35
}