CSS&JS/Frontend Mini Challenge

[FMC]05.Toast Popup

arancia_ 2023. 6. 13. 11:31

데모 : https://ohikmyeong.github.io/frontend-mini-challenges/toast-popup/

 

toast-popup

 

ohikmyeong.github.io

 

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>toast-popup</title>
    <link rel="stylesheet" type="text/css" href="./../common/reset.css"/>
    <link rel="stylesheet" type="text/css" href="./style.css"/>
    <script src="./../common/common.js" defer></script>
    <script src="./main.js" type="module"></script>
</head>
<body>
<main>
    <form id="form-tp">
        <select id="tp-pos-x" title="toast popup coord X">
            <option value="left">left</option>
            <option value="right">right</option>
        </select>
        <select id="tp-pos-y" title="toast popup coord Y">
            <option value="top">top</option>
            <option value="bottom">bottom</option>
        </select>
        <select id="tp-type" title="toast popup type">
            <option value="success">success</option>
            <option value="error">error</option>
            <option value="warning">warning</option>
            <option value="info">info</option>
        </select>
        <input type="text" id="tp-message" value="This is a Toast Message!" placeholder="Enter Mesasge" title="Toast Message" required/>
        <label style="text-align:center;width:100%;margin:20px 0;">
            <span>Duration(1.5 ~ 10s)</span>
            <input type="range" id="tp-duration" min="1500" max="10000" value="3000" step="500" title="toast popup duration"/>
        </label>
        <button type="submit" title="display toast popup" style="width:100%;">Show Toast!</button>
    </form>
 
    <template>
        <section class="toast-popup-container right top">
            <div class="toast-popup success">
                <p class="message">1</p>
                <button class="btn-tp-del"></button>
            </div>
            <div class="toast-popup error">
                <p class="message">2</p>
                <button class="btn-tp-del"></button>
            </div>
            <div class="toast-popup warning">
                <p class="message">3</p>
                <button class="btn-tp-del"></button>
            </div>
            <div class="toast-popup info">
                <p class="message">10000</p>
                <button class="btn-tp-del"></button>
            </div>
        </section>
    </template>
</main>
</body>
</html>
cs

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
@charset "utf-8";
/* main */
main{overflow-x:hidden;}
 
/* form */
#form-tp{
    display:flex;flex-flow:row wrap;
    justify-content:center; align-items:center;
    gap:15px 10px;
    position:relative;
    width:100%; max-width:350px;
}
 
 
#form-tp input{width:100%;}
 
#form-tp select{text-transform:capitalize;}
 
/* 📌[toast popup] */
/* wrap */
.toast-popup-container{
    display:flex; flex-flow:column nowrap;
    gap:10px;
    position:absolute;
}
    /* wrap-position */
    .toast-popup-container.left{
        align-items:flex-start;
        left:20px;
    }
    .toast-popup-container.right{
        align-items:flex-end;
        right:20px;
    }
    .toast-popup-container.top{
        flex-direction:column-reverse;
        top:20px;
    }
    .toast-popup-container.bottom{
        bottom:20px;
    }
 
/* cont */
.toast-popup{
    display:flex;flex-flow:row nowrap;
    align-items:center;
    position:relative;
    padding:0 0 0 10px;
    border-radius:4px;
    font-size:14px; font-weight:600;
    animation-duration:.3s;
    animation-timing-function:ease-in-out;
    animation-direction:both;
}
 
    /* animation */
    @keyframes show-tp-left {
        from{ transform:translateX(-100%);}
    }
    @keyframes show-tp-right {
        from{ transform:translateX(100%);}
    }
    @keyframes hide-tp-left {
        to{ transform:translateX(calc(-100% - 20px));}
    }
    @keyframes hide-tp-right {
        to{ transform:translateX(calc(100% + 20px));}
    }
    .left .toast-popup{
        animation-name:show-tp-left;
    }
    .right .toast-popup{
        animation-name:show-tp-right;
    }
    .left .toast-popup.off{
        animation:hide-tp-left .3s ease-in-out both;
    }
    .right .toast-popup.off{
        animation:hide-tp-right .3s ease-in-out both;
    }
 
 
    /* type */
    .toast-popup.success{
        background:rgb(119, 215, 119); 
    }
    .toast-popup.error{
        background:rgb(255, 104, 104); 
    }
    .toast-popup.warning{
        background:rgb(255, 210, 121); 
    }
    .toast-popup.info{
        background:rgb(255, 253, 202); 
    }
 
    /* before */
    .toast-popup::before{
        margin-right:.8em;
    }
    
    .toast-popup.success::before{
        content:'✓';
    }
    
    .toast-popup.error::before{
        content:'✗';
    }
    
    .toast-popup.warning::before{
        content:'⚠';
    }
    
    .toast-popup.info::before{
        content:'ⓘ';
    }
 
/* delete button */
.btn-tp-del{
    display:inline-block;
    padding:0; margin-left:1em;
    background:rgba(192, 127, 43, 0.124);
    border-radius:0;
    box-shadow:none;
    width:35px; aspect-ratio:1/1;
    font-size:13px;
    transition:none;
    mix-blend-mode:multiply;
}
.btn-tp-del::before,
.btn-tp-del::after{display:none;}
cs

JS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
class ToastPopup{
    constructor(){
        this.init();
    }//constructor
 
    init(){
        document.getElementById('form-tp').addEventListener('submit'this.on_submit);
    }//init
 
    /**
     * on submit form 
     */
    on_submit = e =>{
        e.preventDefault();
 
        const posX = e.target["tp-pos-x"].selectedOptions[0].value;
        const posY = e.target["tp-pos-y"].selectedOptions[0].value;
        const type = e.target["tp-type"].selectedOptions[0].value;
        const message = e.target["tp-message"].value.trim();
        const duration = e.target["tp-duration"].value;
 
        /* make dom */
        const $tpCont = this.get_tp_container(posX,posY);
        const $tp = this.make_toast_popup(message,type);
 
        /* 추가 */
        $tpCont.appendChild($tp);
 
        /* add delete event */
        this.add_on_click_delete($tp);
        setTimeout(()=>{
            this.delete_tp_timeout($tp);
        },duration);
    }//on_submit
 
    /**
     * Find or Make $.toast-popup-container
     * @param {String} posX 
     * @param {String} posY 
     * @returns {DOM} $.toast-popup-container
     */
    get_tp_container(posX="left",posY="top"){
        const $exist = document.querySelector(`.toast-popup-container.${posX}.${posY}`);
        if($exist) return $exist;
        const $cont = document.createElement('SECTION');
        $cont.classList.add("toast-popup-container");
        $cont.classList.add(posX);
        $cont.classList.add(posY);
        document.body.getElementsByTagName('MAIN')[0].appendChild($cont);
        return $cont;
    }//get_tp_container
 
    /**
     * make toast popup message
     * @param {String} message
     * @param {String} type
     * @returns {DOM} $.toast-popup
     */
    make_toast_popup(message,type){
        const $tp = document.createElement('DIV');
        const $msg = document.createElement('P');
        const $del = document.createElement('BUTTON');
 
        $tp.classList.add('toast-popup');
        $tp.classList.add(type);
 
        $msg.classList.add('message');
        $msg.textContent = message;
 
        $del.classList.add('btn-tp-del');
        $del.textContent = '✕';
 
        $tp.appendChild($msg);
        $tp.appendChild($del);
 
        return $tp;
    }//make_toast_popup
 
    /**
     * Delete Toast Popup from Container
     * @param {DOM} $tp 
     */
    add_on_click_delete($tp){
        const $del = $tp.querySelector('.btn-tp-del');
 
        $del.addEventListener('click',()=>{
            this.delete_tp_timeout($tp,300);
        });
    }//add_on_click_delete
 
    /**
     * delete timeout
     * @param {DOM}$tp
     */
 
    delete_tp_timeout($tp){
        $tp.classList.add('off');
 
        $tp.addEventListener('animationend',()=>{
            setTimeout(()=>{
                const $cont = $tp.parentElement;
                $cont.removeChild($tp);
            },300);
        });
    }//delete_tp_timeout
}//ToastPopup
 
 
new ToastPopup();
cs

'CSS&JS > Frontend Mini Challenge' 카테고리의 다른 글

[FMC]04.Light Dark Mode  (0) 2023.06.13
[FMC]03.Telephone Formatter  (0) 2023.04.10
[FMC]02.Guess the Number  (0) 2023.04.10
[FMC]01.Counter  (0) 2023.02.22