Skip to content

Commit 524ca78

Browse files
author
mcarbonell
committed
feat: Day 7 - Final animations and micro-interactions polish
1 parent 295d1c3 commit 524ca78

File tree

5 files changed

+304
-13
lines changed

5 files changed

+304
-13
lines changed

NEXT_STEPS.md

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@
4444
- ✅ Spinner animations
4545
- ✅ Template base.html actualizado
4646

47+
### Refinamiento (Día 7)
48+
- ✅ Animaciones: fadeIn, fadeInUp, scaleIn, slideInLeft
49+
- ✅ Stagger animations (1-6 delays)
50+
- ✅ Micro-interacciones: button ripple, card shine
51+
- ✅ Input focus glow animation
52+
- ✅ Icon bounce on hover
53+
- ✅ Tooltip system con data-tooltip
54+
- ✅ Skeleton loading animation
55+
- ✅ Scroll reveal con IntersectionObserver
56+
- ✅ Smooth scroll behavior
57+
- ✅ animations.js utility script
58+
4759
---
4860

4961
## 🔜 Ahora Mismo (Desplegando)
@@ -60,15 +72,7 @@
6072

6173
### 1. Continuar Diseño (Día 4-7)
6274

63-
**Día 7: Refinamiento** ⬅️ SIGUIENTE
64-
```
65-
□ Animaciones finales
66-
□ Dark mode toggle (opcional)
67-
□ Micro-interacciones
68-
□ Polish general
69-
```
70-
71-
### 2. Otras Opciones
75+
### 2. Próximas Fases
7276

7377
**Opción B: Traducciones (Día 8-9)**
7478
- Verificar traducciones JS
@@ -102,6 +106,6 @@
102106

103107
---
104108

105-
**Progreso**: Día 3/13 completado (23%)
106-
**Próxima sesión**: Día 4 - Hero y Feature Cards
107-
**Tiempo invertido**: ~6-7 horas
109+
**Progreso**: Día 7/13 completado (54%)
110+
**Próxima sesión**: Día 8-9 - Traducciones o Día 10-12 - SEO
111+
**Tiempo invertido**: ~7-8 horas (¡en 1 sesión!)

web/css/style-v2.css

Lines changed: 235 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,39 @@ a:hover {
531531
}
532532
}
533533

534+
@keyframes fadeInUp {
535+
from {
536+
opacity: 0;
537+
transform: translateY(30px);
538+
}
539+
to {
540+
opacity: 1;
541+
transform: translateY(0);
542+
}
543+
}
544+
545+
@keyframes scaleIn {
546+
from {
547+
opacity: 0;
548+
transform: scale(0.9);
549+
}
550+
to {
551+
opacity: 1;
552+
transform: scale(1);
553+
}
554+
}
555+
556+
@keyframes slideInLeft {
557+
from {
558+
opacity: 0;
559+
transform: translateX(-30px);
560+
}
561+
to {
562+
opacity: 1;
563+
transform: translateX(0);
564+
}
565+
}
566+
534567
@keyframes pulse {
535568
0%, 100% {
536569
opacity: 1;
@@ -540,14 +573,43 @@ a:hover {
540573
}
541574
}
542575

576+
@keyframes bounce {
577+
0%, 100% {
578+
transform: translateY(0);
579+
}
580+
50% {
581+
transform: translateY(-10px);
582+
}
583+
}
584+
543585
.fade-in {
544-
animation: fadeIn 0.5s ease-in;
586+
animation: fadeIn 0.6s ease-out;
587+
}
588+
589+
.fade-in-up {
590+
animation: fadeInUp 0.6s ease-out;
591+
}
592+
593+
.scale-in {
594+
animation: scaleIn 0.4s ease-out;
595+
}
596+
597+
.slide-in-left {
598+
animation: slideInLeft 0.5s ease-out;
545599
}
546600

547601
.loading {
548602
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
549603
}
550604

605+
/* Stagger animations */
606+
.stagger-1 { animation-delay: 0.1s; }
607+
.stagger-2 { animation-delay: 0.2s; }
608+
.stagger-3 { animation-delay: 0.3s; }
609+
.stagger-4 { animation-delay: 0.4s; }
610+
.stagger-5 { animation-delay: 0.5s; }
611+
.stagger-6 { animation-delay: 0.6s; }
612+
551613
/* ====================
552614
NAVIGATION
553615
==================== */
@@ -969,3 +1031,175 @@ section h3::before {
9691031
outline: 2px solid var(--primary);
9701032
outline-offset: 2px;
9711033
}
1034+
1035+
/* ====================
1036+
MICRO-INTERACTIONS
1037+
==================== */
1038+
1039+
/* Smooth scroll */
1040+
html {
1041+
scroll-behavior: smooth;
1042+
}
1043+
1044+
/* Link hover effect */
1045+
a:not(.btn) {
1046+
position: relative;
1047+
transition: color var(--transition-fast);
1048+
}
1049+
1050+
/* Button ripple effect */
1051+
.btn {
1052+
position: relative;
1053+
overflow: hidden;
1054+
}
1055+
1056+
.btn::after {
1057+
content: '';
1058+
position: absolute;
1059+
top: 50%;
1060+
left: 50%;
1061+
width: 0;
1062+
height: 0;
1063+
border-radius: 50%;
1064+
background: rgba(255, 255, 255, 0.3);
1065+
transform: translate(-50%, -50%);
1066+
transition: width 0.6s, height 0.6s;
1067+
}
1068+
1069+
.btn:active::after {
1070+
width: 300px;
1071+
height: 300px;
1072+
}
1073+
1074+
/* Card shine effect */
1075+
.card {
1076+
position: relative;
1077+
overflow: hidden;
1078+
}
1079+
1080+
.card::after {
1081+
content: '';
1082+
position: absolute;
1083+
top: -50%;
1084+
left: -50%;
1085+
width: 200%;
1086+
height: 200%;
1087+
background: linear-gradient(
1088+
45deg,
1089+
transparent 30%,
1090+
rgba(255, 255, 255, 0.1) 50%,
1091+
transparent 70%
1092+
);
1093+
transform: translateX(-100%);
1094+
transition: transform 0.6s;
1095+
}
1096+
1097+
.card:hover::after {
1098+
transform: translateX(100%);
1099+
}
1100+
1101+
/* Input focus glow */
1102+
.form-control:focus,
1103+
.form-select:focus {
1104+
animation: inputGlow 0.3s ease-out;
1105+
}
1106+
1107+
@keyframes inputGlow {
1108+
0% {
1109+
box-shadow: 0 0 0 0 rgba(19, 164, 236, 0.4);
1110+
}
1111+
100% {
1112+
box-shadow: 0 0 0 3px rgba(19, 164, 236, 0.1);
1113+
}
1114+
}
1115+
1116+
/* Icon bounce on hover */
1117+
.material-symbols-outlined {
1118+
transition: transform var(--transition-fast);
1119+
}
1120+
1121+
.btn:hover .material-symbols-outlined,
1122+
.card:hover .material-symbols-outlined {
1123+
animation: bounce 0.6s ease-in-out;
1124+
}
1125+
1126+
/* Tooltip */
1127+
[data-tooltip] {
1128+
position: relative;
1129+
cursor: help;
1130+
}
1131+
1132+
[data-tooltip]::before {
1133+
content: attr(data-tooltip);
1134+
position: absolute;
1135+
bottom: 100%;
1136+
left: 50%;
1137+
transform: translateX(-50%) translateY(-8px);
1138+
padding: var(--spacing-xs) var(--spacing-sm);
1139+
background: var(--text-primary);
1140+
color: white;
1141+
font-size: var(--text-xs);
1142+
white-space: nowrap;
1143+
border-radius: var(--radius-sm);
1144+
opacity: 0;
1145+
pointer-events: none;
1146+
transition: opacity var(--transition-fast), transform var(--transition-fast);
1147+
}
1148+
1149+
[data-tooltip]:hover::before {
1150+
opacity: 1;
1151+
transform: translateX(-50%) translateY(-4px);
1152+
}
1153+
1154+
/* Skeleton loading */
1155+
.skeleton {
1156+
background: linear-gradient(
1157+
90deg,
1158+
var(--bg-light) 25%,
1159+
var(--bg-gray) 50%,
1160+
var(--bg-light) 75%
1161+
);
1162+
background-size: 200% 100%;
1163+
animation: skeleton-loading 1.5s infinite;
1164+
border-radius: var(--radius-md);
1165+
}
1166+
1167+
@keyframes skeleton-loading {
1168+
0% {
1169+
background-position: 200% 0;
1170+
}
1171+
100% {
1172+
background-position: -200% 0;
1173+
}
1174+
}
1175+
1176+
/* Scroll reveal */
1177+
.scroll-reveal {
1178+
opacity: 0;
1179+
transform: translateY(30px);
1180+
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
1181+
}
1182+
1183+
.scroll-reveal.revealed {
1184+
opacity: 1;
1185+
transform: translateY(0);
1186+
}
1187+
1188+
/* Badge pulse */
1189+
.badge-pulse {
1190+
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
1191+
}
1192+
1193+
/* Floating animation */
1194+
.floating {
1195+
animation: floating 3s ease-in-out infinite;
1196+
}
1197+
1198+
@keyframes floating {
1199+
0%, 100% {
1200+
transform: translateY(0);
1201+
}
1202+
50% {
1203+
transform: translateY(-10px);
1204+
}
1205+
}

web/es/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ <h5 class="card-title">Editar Imagen con IA</h5>
455455
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
456456
<script src="/i18n/language-selector.js"></script>
457457
<script src="js/main.js"></script>
458+
<script src="/js/animations.js"></script>
458459
<script src="/js/cookie-consent.js"></script>
459460
<script src="/js/analytics.js"></script>
460461

web/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ <h5 class="card-title">Edit Image with AI</h5>
452452
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
453453
<script src="/i18n/language-selector.js"></script>
454454
<script src="js/main.js"></script>
455+
<script src="/js/animations.js"></script>
455456
<script src="/js/cookie-consent.js"></script>
456457
<script src="/js/analytics.js"></script>
457458

web/js/animations.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* Animation utilities for FastTools
3+
* Scroll reveal and micro-interactions
4+
*/
5+
6+
// Scroll reveal observer
7+
const observeScrollReveal = () => {
8+
const elements = document.querySelectorAll('.scroll-reveal');
9+
10+
if (!elements.length) return;
11+
12+
const observer = new IntersectionObserver((entries) => {
13+
entries.forEach(entry => {
14+
if (entry.isIntersecting) {
15+
entry.target.classList.add('revealed');
16+
observer.unobserve(entry.target);
17+
}
18+
});
19+
}, {
20+
threshold: 0.1,
21+
rootMargin: '0px 0px -50px 0px'
22+
});
23+
24+
elements.forEach(el => observer.observe(el));
25+
};
26+
27+
// Stagger animation for children
28+
const staggerChildren = (parent, className = 'fade-in-up') => {
29+
const children = parent.querySelectorAll(':scope > *');
30+
children.forEach((child, index) => {
31+
child.classList.add(className, `stagger-${Math.min(index + 1, 6)}`);
32+
});
33+
};
34+
35+
// Initialize on DOM ready
36+
if (document.readyState === 'loading') {
37+
document.addEventListener('DOMContentLoaded', () => {
38+
observeScrollReveal();
39+
40+
// Auto-stagger tool grids
41+
const toolGrids = document.querySelectorAll('.row.g-4');
42+
toolGrids.forEach(grid => {
43+
const cards = grid.querySelectorAll('.card');
44+
cards.forEach((card, index) => {
45+
card.classList.add('fade-in-up', `stagger-${Math.min(index + 1, 6)}`);
46+
});
47+
});
48+
});
49+
} else {
50+
observeScrollReveal();
51+
}

0 commit comments

Comments
 (0)