├── img
├── cloud.jpg
├── cloud1.png
├── loveHand.png
├── artHeart.webp
├── squareLove.jpg
├── tickHeart.png
└── paperHeart.webp
├── main.js
├── index.html
└── main.css
/img/cloud.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phamvulinh18/thutinh/HEAD/img/cloud.jpg
--------------------------------------------------------------------------------
/img/cloud1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phamvulinh18/thutinh/HEAD/img/cloud1.png
--------------------------------------------------------------------------------
/img/loveHand.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phamvulinh18/thutinh/HEAD/img/loveHand.png
--------------------------------------------------------------------------------
/img/artHeart.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phamvulinh18/thutinh/HEAD/img/artHeart.webp
--------------------------------------------------------------------------------
/img/squareLove.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phamvulinh18/thutinh/HEAD/img/squareLove.jpg
--------------------------------------------------------------------------------
/img/tickHeart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phamvulinh18/thutinh/HEAD/img/tickHeart.png
--------------------------------------------------------------------------------
/img/paperHeart.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phamvulinh18/thutinh/HEAD/img/paperHeart.webp
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | // Thay đổi nội dung búc thư ở đây
2 | var letterContent =" Cảm ơn em đã dành thời gian để nhìn những trò trẻ con của anhh và anh có những điều muốn gởi gắm đến tình iu của anhh❤️. Cảm ơn em đã đến bên anhh những lúc anh cô đơn buồn tủi nhất.Cuộc sống thực sự chẳng có ý nghĩa gì nếu không có em. Em làm cho anh luôn cảm thấy đặc biệt và hoàn hảo. Anh chẳng biết nói gì ngoài lời cảm ơn em, anh rất yêu em💕"
3 |
4 | // Tốc độ viết chữ. Số càng nhỏ tốc độ càng nhanh. 50 là tốc độ khá phù hợp
5 | durationWrite = 50
6 |
7 | // Hiệu ứng gõ chữ
8 |
9 | function effectWrite () {
10 | var boxLetter = document.querySelector(".letterContent")
11 | letterContentSplited = letterContent.split("")
12 |
13 | letterContentSplited.forEach((val, index) => {
14 | setTimeout(() => {
15 | boxLetter.innerHTML += val
16 | }, durationWrite* index)
17 | })
18 | }
19 |
20 | window.addEventListener("load", () => {
21 | setTimeout(() => {
22 | document.querySelector(".container").classList.add("active")
23 | }, 500)
24 | })
25 |
26 | var openBtn = document.querySelector(".openBtn")
27 | openBtn.addEventListener("click", () => {
28 | document.querySelector(".cardValentine").classList.add("active")
29 | document.querySelector(".container").classList.add("close")
30 | })
31 |
32 | var cardValentine = document.querySelector(".cardValentine")
33 |
34 | cardValentine.addEventListener("click", () => {
35 | cardValentine.classList.toggle("open")
36 |
37 | if(cardValentine.className.indexOf("open") != -1) {
38 | setTimeout(effectWrite, 500)
39 | } else {
40 | setTimeout(() => {
41 | document.querySelector(".letterContent").innerHTML = ""
42 | }, 1000)
43 | }
44 | })
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
13 |
14 |
15 |
16 | Valentine Day
17 |
18 |
19 |
20 |
21 |

22 |

23 |

24 |

25 |

26 |

27 |
28 |
29 |
Chào mừng em dến
30 |
với thế giới của anhh
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
50 |
51 |
Hãy chạm vào tấm thiệp
52 |
53 |
54 |

55 |
56 |
57 |
58 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/main.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | user-select: none;
6 | }
7 |
8 | html, body {
9 | height: 100%;
10 | width: 100%;
11 | }
12 |
13 | .container {
14 | position: relative;
15 | height: 100%;
16 | width: 100%;
17 | background-color: #fc6885;
18 | overflow: hidden;
19 | }
20 |
21 | .paperHeart {
22 | position: absolute;
23 | height: 100px;
24 | top: 80%;
25 | opacity: 0;
26 | filter: drop-shadow(0 0 20px rgb(247, 176, 176));
27 | animation: hiddenHeart 3.1s linear forwards,flyHeart 4s ease-in-out calc(var(--time) + 3.1s) infinite;
28 | }
29 |
30 | .paperHeart1 {
31 | left: 50px;
32 | }
33 |
34 | .paperHeart2 {
35 | left: 250px;
36 | }
37 |
38 | .paperHeart3 {
39 | left: 500px;
40 | }
41 |
42 | .paperHeart4 {
43 | left: 800px;
44 | }
45 |
46 | .paperHeart5 {
47 | left: 1100px;
48 | }
49 |
50 | .paperHeart6 {
51 | left: 1400px;
52 | }
53 |
54 | .boxCloud {
55 | position: absolute;
56 | bottom: 0;
57 | left: 0;
58 | height: 300px;
59 | width: 100%;
60 | background-color: transparent;
61 | }
62 |
63 | .container .cloud {
64 | position: absolute;
65 | top: 120%;
66 | left: -50px;
67 | }
68 |
69 | .container .cloud1 {
70 | position: absolute;
71 | top: 120%;
72 | left: -50px;
73 | }
74 |
75 | .container .cloud2 {
76 | position: absolute;
77 | top: 120%;
78 | left: -50px;
79 | }
80 |
81 | .container.active.close {
82 | .btnBox {
83 | animation: disappearBtn 1s ease-in-out forwards;
84 | }
85 |
86 | .boxTitle {
87 | animation: disappearBoxTitle 1s ease-in-out forwards;
88 | }
89 | }
90 |
91 | @keyframes disappearBtn {
92 | from {
93 | top: 50%;
94 | }
95 |
96 | to {
97 | top: 150%;
98 | }
99 | }
100 |
101 | @keyframes disappearBoxTitle {
102 | from {
103 | top: 10%;
104 | }
105 |
106 | to {
107 | top: -50%;
108 | }
109 | }
110 |
111 | .container.active .cloud {
112 | position: absolute;
113 | top: 0;
114 | left: -50px;
115 | height: 200px;
116 | width: 200px;
117 | background-color: #ffb3c1;
118 | border-radius: 50%;
119 | box-shadow: 120px -20px #ffb3c1, 240px -40px #ffb3c1, 360px -20px #ffb3c1,
120 | 480px 0px #ffb3c1, 600px -10px #ffb3c1, 720px 10px #ffb3c1, 840px 20px #ffb3c1,
121 | 960px 0px #ffb3c1, 1080px 40px #ffb3c1, 1200px 20px #ffb3c1, 1320px 0px #ffb3c1,
122 | 1440px -20px #ffb3c1;
123 | transition: .8s;
124 | transition-delay: 2.2s;
125 | animation: animateCloud 3s ease-in-out 1s infinite;
126 | }
127 |
128 | @keyframes animateCloud {
129 | 0% {
130 | top: 0;
131 | }
132 |
133 | 25% {
134 | top: 10px;
135 | }
136 |
137 | 50% {
138 | top: -10px;
139 | }
140 |
141 | 75% {
142 | top: 10px;
143 | }
144 |
145 | 100% {
146 | top: 0;
147 | }
148 |
149 | }
150 |
151 | @keyframes animateCloud1 {
152 | 0% {
153 | top: 75;
154 | }
155 |
156 | 25% {
157 | top: 85;
158 | }
159 |
160 | 50% {
161 | top: 65;
162 | }
163 |
164 | 75% {
165 | top: 85;
166 | }
167 |
168 | 100% {
169 | top: 75;
170 | }
171 |
172 | }
173 |
174 | @keyframes animateCloud2 {
175 | 0% {
176 | top: 150;
177 | }
178 |
179 | 25% {
180 | top: 160px;
181 | }
182 |
183 | 50% {
184 | top: 140px;
185 | }
186 |
187 | 75% {
188 | top: 160px;
189 | }
190 |
191 | 100% {
192 | top: 150;
193 | }
194 |
195 | }
196 |
197 | .container.active .cloud1 {
198 | position: absolute;
199 | top: 75px;
200 | left: -50px;
201 | content: "";
202 | height: 200px;
203 | width: 200px;
204 | background-color: #ffccd5;
205 | border-radius: 50%;
206 | box-shadow: 120px -20px #ffccd5, 240px -40px #ffccd5, 360px -20px #ffccd5,
207 | 480px 0px #ffccd5, 600px -10px #ffccd5, 720px 10px #ffccd5, 840px 20px #ffccd5,
208 | 960px 0px #ffccd5, 1080px 40px #ffccd5, 1200px 20px #ffccd5, 1320px 0px #ffccd5,
209 | 1440px -20px #ffccd5, 1560px 0px #ffccd5;
210 | transition: .8s;
211 | transition-delay: 1.3s;
212 | animation: animateClou1 3s ease-in-out 1.5s infinite;
213 | }
214 |
215 | .container.active .cloud2 {
216 | position: absolute;
217 | top: 150px;
218 | left: -50px;
219 | content: "";
220 | height: 200px;
221 | width: 200px;
222 | background-color: white;
223 | border-radius: 50%;
224 | box-shadow: 120px -20px white, 240px -20px white, 360px -20px white,
225 | 480px 0px white, 600px -10px white, 720px 10px white, 840px 20px white,
226 | 960px 0px white, 1080px 40px white, 1200px 20px white, 1320px 0px white,
227 | 1440px -20px white, 1560px 0px white;
228 | transition: .8s;
229 | transition-delay: .5s;
230 | animation: animateCloud2 3s ease-in-out 2s infinite;
231 | }
232 |
233 | .boxTitle {
234 | position: absolute;
235 | top: 120%;
236 | left: 50%;
237 | transform: translateX(-50%);
238 | font-family: "Rubik Glitch Pop", system-ui;
239 | font-weight: 400;
240 | font-style: normal;
241 | font-size: 120px;
242 | color: pink;
243 | height: fit-content;
244 | width: fit-content;
245 | display: flex;
246 | justify-content: center;
247 | align-items: center;
248 | flex-wrap: wrap;
249 | text-shadow: 0 0 20px white;
250 | animation: appearTitle 2s linear 3.1s forwards, floatingWords 4s ease-in-out infinite;
251 |
252 | }
253 |
254 | .container .btnBox {
255 | position: absolute;
256 | top: 150%;
257 | left: 50%;
258 | transform: translate(-50%, -50%);
259 | height: 160px;
260 | width: 400px;
261 | opacity: 1;
262 | }
263 |
264 | .container.active .btnBox {
265 | opacity: 1;
266 | transition: 1s;
267 | transition-delay: 5s;
268 | animation: appearBtnBox 2s ease-in-out 5s forwards,animateOpenBtn 2s ease-in-out 5s infinite;
269 | }
270 |
271 | @keyframes appearBtnBox {
272 | from {
273 | top: 150%;
274 | }
275 |
276 | to {
277 | top: 50%;
278 | }
279 | }
280 |
281 | .cloudBtn {
282 | position: relative;
283 | height: 100px;
284 | width: 100px;
285 | background-color: #fc6885;
286 | border-radius: 50%;
287 | box-shadow: 60px 0 #fc6885, 120px 0 #fc6885, 180px 0 #fc6885, 240px 0 #fc6885,
288 | 300px 0 #fc6885, 300px 60px #fc6885, 240px 60px #fc6885, 180px 60px #fc6885,
289 | 120px 60px #fc6885, 60px 60px #fc6885, 0 60px #fc6885;
290 | }
291 |
292 | .cloudBtn::before {
293 | position: absolute;
294 | content: "";
295 | top: 50%;
296 | left: 50%;
297 | transform: translate(-50%, -50%);
298 | height: 80px;
299 | width: 80px;
300 | background-color: white;
301 | border-radius: 50%;
302 | box-shadow: 60px 0 white, 120px 0 white, 180px 0 white, 240px 0 white,
303 | 300px 0 white, 300px 60px white, 240px 60px white, 180px 60px white,
304 | 120px 60px white, 60px 60px white, 0 60px white;
305 | }
306 |
307 | .openBtn {
308 | position: absolute;
309 | top: 50%;
310 | left: 50%;
311 | transform: translate(-50%, -50%);
312 | width: 100%;
313 | height: 100%;
314 | font-family: "Rubik Glitch Pop", system-ui;
315 | font-weight: 400;
316 | font-style: normal;
317 | font-size: 40px;
318 | color: #fc6885;
319 | background-color: transparent;
320 | border: none;
321 | text-shadow: 0 0 10px pink;
322 | }
323 |
324 | .openBtn:hover {
325 | cursor: grab;
326 | }
327 |
328 | /* OPEN */
329 | .container.active.open {
330 | .boxTitle {
331 | animation: none;
332 | top: -40%;
333 | }
334 |
335 | .btnBox {
336 | animation: none;
337 | top: 140%;
338 | }
339 |
340 | }
341 |
342 | .cardValentine {
343 | position: absolute;
344 | top: 200%;
345 | left: 50%;
346 | opacity: 0;
347 | transform: translate(-50%, -50%);
348 | height: 600px;
349 | width: 800px;
350 | background-color: transparent;
351 | transition: .5;
352 | }
353 |
354 | .cardValentine.active {
355 | position: absolute;
356 | top: 50%;
357 | left: 50%;
358 | opacity: 1;
359 | transform: translate(-50%, -50%);
360 | height: 600px;
361 | width: 800px;
362 | background-color: transparent;
363 | transition: .5;
364 | animation: animateCard 2s ease-in-out forwards;
365 | }
366 |
367 | @keyframes animateCard {
368 | from {
369 | top: 200%;
370 | }
371 |
372 | to {
373 | top: 50%;
374 | }
375 | }
376 |
377 | .cardValentine .left {
378 | z-index: 2;
379 | position: absolute;
380 | top: 0;
381 | left: 50%;
382 | height: 100%;
383 | width: 50%;
384 | border-radius: 10px;
385 | transition: .5s;
386 | padding: 20px;
387 | }
388 |
389 | .cardValentine .left .leftFront {
390 | position: absolute;
391 | top: 0;
392 | left: 0;
393 | height: 100%;
394 | width: 100%;
395 | background-color: #f35553;
396 | border-radius: inherit;
397 | transition: .5s;
398 | display: flex;
399 | justify-content: center;
400 | align-items: center;
401 | box-shadow: 0 0 10px lightgray;
402 | border-left: 10px solid #c9413f;
403 | }
404 |
405 | .boxShadow {
406 | filter: drop-shadow(0 0 10px white);
407 | height: fit-content;
408 | width: fit-content;
409 | }
410 |
411 | .boxTitleCard {
412 | position: relative;
413 | height: 300px;
414 | width: 300px;
415 | display: flex;
416 | justify-content: center;
417 | background-color: white;
418 | clip-path: polygon(10% 0, 35% 0, 50% 23%, 65% 0, 90% 0, 100% 30%, 50% 100%, 0 30%);
419 | }
420 |
421 | .boxTitleCard::before {
422 | position: absolute;
423 | content: "";
424 | top: 50%;
425 | left: 50%;
426 | transform: translate(-50%, -50%);
427 | height: 280px;
428 | width: 280px;
429 | background-color: #f35553;
430 | clip-path: polygon(10% 0, 35% 0, 50% 23%, 65% 0, 90% 0, 100% 30%, 50% 100%, 0 30%);
431 | }
432 |
433 | .boxTitleCard::after {
434 | position: absolute;
435 | content: "";
436 | top: 50%;
437 | left: 50%;
438 | transform: translate(-50%, -50%);
439 | height: 250px;
440 | width: 250px;
441 | background-color: white;
442 | clip-path: polygon(10% 0, 35% 0, 50% 23%, 65% 0, 90% 0, 100% 30%, 50% 100%, 0 30%);
443 | }
444 |
445 |
446 | .titleCard {
447 | font-family: "Protest Revolution", sans-serif;
448 | font-weight: 400;
449 | font-style: normal;
450 | font-size: 60px;
451 | color: #f35553;
452 | margin-top: 80px;
453 | }
454 |
455 | .cardValentine .left .leftBack {
456 | position: absolute;
457 | top: 0;
458 | left: 0;
459 | transform: rotateY(180deg);
460 | backface-visibility: hidden;
461 | background-color: #f35553;
462 | height: 100%;
463 | width: 100%;
464 | border-radius: inherit;
465 | border-right: 10px solid #c9413f;
466 | display: flex;
467 | justify-content: center;
468 | align-items: center;
469 | transition: .5s;
470 | }
471 |
472 | .artHeart {
473 | width: 90%;
474 | height: auto;
475 | filter: drop-shadow(0 0 5px white);
476 | }
477 |
478 | .des {
479 | position: absolute;
480 | bottom: 40px;
481 | left: 50%;
482 | transform: translateX(-50%);
483 | font-family: "Protest Revolution", sans-serif;
484 | font-weight: 400;
485 | font-size: 24px;
486 | font-style: normal;
487 | width: 100%;
488 | text-align: center;
489 | }
490 |
491 | .cardValentine .right {
492 | z-index: 1;
493 | position: absolute;
494 | top: 0;
495 | left: 50%;
496 | height: 100%;
497 | width: 50%;
498 | background-color: #f35553;
499 | border-radius: 10px;
500 | display: flex;
501 | justify-content: center;
502 | align-items: center;
503 | border-left: 10px solid #c9413f;
504 | transition: .5s;
505 | }
506 |
507 | .rightContent {
508 | font-size: 20px;
509 | height: 95%;
510 | width: 90%;
511 | background-color: wheat;
512 | border-radius: 5px;
513 | padding: 20px 15px;
514 | overflow: auto;
515 | }
516 |
517 | .rightContent::-webkit-scrollbar {
518 | background-color: white;
519 | width: 6px;
520 | }
521 |
522 | .rightContent::-webkit-scrollbar-thumb {
523 | background-color: #d34745;
524 | }
525 |
526 | .letterContent {
527 | font-family: "Pacifico", cursive;
528 | font-weight: 400;
529 | font-style: normal;
530 | }
531 |
532 | .cardValentine.active.open {
533 | top: 50%;
534 | left: 50%;
535 | transform: translate(-50%, -50%);
536 | transition: .5s;
537 |
538 | .left {
539 | transform-style: preserve-3d;
540 | transform: rotateY(-180deg);
541 | transform-origin: left;
542 | background-color: red;
543 | transition: .5s;
544 | }
545 |
546 | .leftFront {
547 | backface-visibility: hidden;
548 | }
549 |
550 | }
551 |
552 | @keyframes appearTitle {
553 | to {
554 | top: 10%;
555 | }
556 | }
557 |
558 | @keyframes floatingWords {
559 | 0% {
560 | transform: translateX(-50%);
561 | }
562 |
563 | 25% {
564 | transform: translateX(-50%) translateY(-50px);
565 | }
566 |
567 | 50% {
568 | transform: translateX(-50%) translateY(50px);
569 | }
570 |
571 | 75% {
572 | transform: translateX(-50%) translateY(0);
573 | }
574 | }
575 |
576 | @keyframes flyHeart {
577 | to {
578 | top: -20%;
579 | }
580 | }
581 |
582 | @keyframes hiddenHeart {
583 | 0% {
584 | opacity: 0;
585 | }
586 |
587 | 95% {
588 | opacity: 0;
589 | }
590 |
591 | 100% {
592 | opacity: 1;
593 | }
594 | }
595 |
596 | @keyframes animateOpenBtn {
597 | 25% {
598 | top: 50%;
599 | }
600 |
601 | 50% {
602 | top: calc(50% + 2px);
603 | }
604 |
605 | 75% {
606 | top: calc(50% - 2px);
607 | }
608 |
609 | 100% {
610 | top: 50%;
611 | }
612 | }
--------------------------------------------------------------------------------