├── .github └── FUNDING.yml ├── README.md ├── example ├── index.html ├── script.js └── style.css ├── saber-toast.css └── saber-toast.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: ahmed0saber # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # saber-toast 2 | 3 | Saber Toast is a library for all your toasts 4 | 5 | ## example 6 | 7 | https://ahmed0saber.github.io/saber-toast/example/ 8 | 9 | ## documentation on cssscript 10 | 11 | https://www.cssscript.com/stylish-toast-saber/ 12 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Example | Saber Toast 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |

Example | Saber Toast

19 |

Saber Toast is a library for all your toasts

20 |
21 | 22 | 23 | 24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /example/script.js: -------------------------------------------------------------------------------- 1 | document.querySelector(".success-btn").addEventListener('click', () => { 2 | saberToast.success({ 3 | title: "تمت العملية بنجاح", 4 | text: "تم اضافة المنتج الى السلة", 5 | delay: 200, 6 | duration: 2600, 7 | rtl: true, 8 | position: "top-left" 9 | }) 10 | }) 11 | 12 | document.querySelector(".error-btn").addEventListener('click', () => { 13 | saberToast.error({ 14 | title: "حدث خطأ ما", 15 | text: "يرجى المحاولة مرة اخرى", 16 | delay: 200, 17 | duration: 2600, 18 | rtl: true, 19 | position: "bottom-right" 20 | }) 21 | }) 22 | 23 | document.querySelector(".warn-btn").addEventListener('click', () => { 24 | saberToast.warn({ 25 | title: "حدث خطأ ما", 26 | text: "يرجى المحاولة مرة اخرى", 27 | delay: 200, 28 | duration: 2600, 29 | rtl: true, 30 | position: "bottom-right" 31 | }) 32 | }) 33 | 34 | document.querySelector(".info-btn").addEventListener('click', () => { 35 | saberToast.info({ 36 | title: "حدث خطأ ما", 37 | text: "يرجى المحاولة مرة اخرى", 38 | delay: 200, 39 | duration: 2600, 40 | rtl: true, 41 | position: "bottom-right" 42 | }) 43 | }) -------------------------------------------------------------------------------- /example/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | position: relative; 6 | border: none; 7 | outline: none; 8 | font-family: 'Glory', 'Cairo', sans-serif; 9 | } 10 | 11 | body { 12 | min-height: 100vh; 13 | display: grid; 14 | place-items: center; 15 | background-color: #F7F7F7; 16 | padding: 12px; 17 | } 18 | 19 | main { 20 | padding: 12px; 21 | border: 2px solid #323232; 22 | width: 100%; 23 | max-width: 600px; 24 | border-radius: 6px; 25 | -webkit-border-radius: 6px; 26 | -moz-border-radius: 6px; 27 | -ms-border-radius: 6px; 28 | -o-border-radius: 6px; 29 | } 30 | 31 | .example h1 { 32 | color: #323232; 33 | font-size: 32px; 34 | } 35 | 36 | .example p { 37 | color: #323232; 38 | margin: 10px 0 16px 0; 39 | font-size: 22px; 40 | } 41 | 42 | .example .btns { 43 | display: flex; 44 | align-items: stretch; 45 | flex-wrap: wrap; 46 | gap: 12px; 47 | } 48 | 49 | .example button { 50 | padding: 12px; 51 | color: #F7F7F7; 52 | font-size: 20px; 53 | cursor: pointer; 54 | border-radius: 6px; 55 | -webkit-border-radius: 6px; 56 | -moz-border-radius: 6px; 57 | -ms-border-radius: 6px; 58 | -o-border-radius: 6px; 59 | width: calc(50% - 6px); 60 | } 61 | 62 | .example .error-btn { 63 | background-color: #dc3545; 64 | } 65 | 66 | .example .success-btn { 67 | background-color: #28a745; 68 | } 69 | 70 | .example .warn-btn { 71 | background-color: #BF9725; 72 | } 73 | 74 | .example .info-btn { 75 | background-color: #5953FF; 76 | } -------------------------------------------------------------------------------- /saber-toast.css: -------------------------------------------------------------------------------- 1 | .saber-toasts-containers { 2 | position: fixed; 3 | width: 320px; 4 | display: flex; 5 | flex-direction: column; 6 | gap: 12px; 7 | direction: rtl; 8 | } 9 | 10 | .saber-toasts-container-bottom-right { 11 | right: 20px; 12 | bottom: 20px; 13 | } 14 | 15 | .saber-toasts-container-top-right { 16 | right: 20px; 17 | top: 20px; 18 | flex-direction: column-reverse; 19 | } 20 | 21 | .saber-toasts-container-bottom-left { 22 | left: 20px; 23 | bottom: 20px; 24 | } 25 | 26 | .saber-toasts-container-top-left { 27 | left: 20px; 28 | top: 20px; 29 | flex-direction: column-reverse; 30 | } 31 | 32 | .saber-toast { 33 | width: 320px; 34 | height: 80px; 35 | background-color: #FFF; 36 | box-shadow: 0px 0px 10px #0000001A; 37 | border-radius: 10px; 38 | -webkit-border-radius: 10px; 39 | -moz-border-radius: 10px; 40 | -ms-border-radius: 10px; 41 | -o-border-radius: 10px; 42 | display: flex; 43 | align-items: stretch; 44 | gap: 12px; 45 | } 46 | 47 | .saber-toast .right-border { 48 | width: 6px; 49 | border-radius: 0px 10px 10px 0px; 50 | -webkit-border-radius: 0px 10px 10px 0px; 51 | -moz-border-radius: 0px 10px 10px 0px; 52 | -ms-border-radius: 0px 10px 10px 0px; 53 | -o-border-radius: 0px 10px 10px 0px; 54 | margin: 0 0 0 2px; 55 | } 56 | 57 | .saber-toast .state-icon-holder { 58 | width: 40px; 59 | display: grid; 60 | place-items: center; 61 | } 62 | 63 | .saber-toast .state-icon { 64 | width: 40px; 65 | height: 40px; 66 | display: grid; 67 | place-items: center; 68 | border-radius: 50%; 69 | -webkit-border-radius: 50%; 70 | -moz-border-radius: 50%; 71 | -ms-border-radius: 50%; 72 | -o-border-radius: 50%; 73 | } 74 | 75 | .saber-toast .state-icon svg { 76 | width: 50%; 77 | } 78 | 79 | .saber-toast .text-container { 80 | display: flex; 81 | flex-direction: column; 82 | justify-content: center; 83 | gap: 6px; 84 | flex: 1; 85 | } 86 | 87 | .saber-toast .title { 88 | font-size: 12px; 89 | } 90 | 91 | .saber-toast .text { 92 | font-size: 13px; 93 | color: #18181A; 94 | font-weight: bold; 95 | } 96 | 97 | .saber-toast .close-icon-holder { 98 | padding: 12px; 99 | } 100 | 101 | .saber-toast .close-icon { 102 | width: 22px; 103 | height: 22px; 104 | background-color: #F1F1F1; 105 | border-radius: 50%; 106 | -webkit-border-radius: 50%; 107 | -moz-border-radius: 50%; 108 | -ms-border-radius: 50%; 109 | -o-border-radius: 50%; 110 | display: grid; 111 | place-items: center; 112 | cursor: pointer; 113 | } 114 | 115 | .saber-toast .close-icon svg { 116 | width: 70%; 117 | color: rgba(0, 0, 0, 0.5); 118 | } 119 | 120 | @media (max-width: 520px) { 121 | .saber-toasts-containers { 122 | width: 240px; 123 | } 124 | 125 | .saber-toast { 126 | width: 240px; 127 | height: 66px; 128 | gap: 8px; 129 | } 130 | 131 | .saber-toast .state-icon-holder { 132 | width: 30px; 133 | } 134 | 135 | .saber-toast .state-icon { 136 | width: 30px; 137 | height: 30px; 138 | } 139 | 140 | .saber-toast .title { 141 | font-size: 11px; 142 | } 143 | 144 | .saber-toast .text { 145 | font-size: 12px; 146 | } 147 | 148 | .saber-toast .text-container { 149 | gap: 3px; 150 | } 151 | 152 | .saber-toast .close-icon-holder { 153 | padding: 8px; 154 | } 155 | 156 | .saber-toast .close-icon { 157 | width: 18px; 158 | height: 18px; 159 | } 160 | } -------------------------------------------------------------------------------- /saber-toast.js: -------------------------------------------------------------------------------- 1 | const initSaberToast = () => { 2 | const bottomRightContainer = document.createElement('div') 3 | bottomRightContainer.classList.add('saber-toasts-container-bottom-right') 4 | bottomRightContainer.classList.add('saber-toasts-containers') 5 | document.body.append(bottomRightContainer) 6 | 7 | const topRightContainer = document.createElement('div') 8 | topRightContainer.classList.add('saber-toasts-container-top-right') 9 | topRightContainer.classList.add('saber-toasts-containers') 10 | document.body.append(topRightContainer) 11 | 12 | const bottomLeftContainer = document.createElement('div') 13 | bottomLeftContainer.classList.add('saber-toasts-container-bottom-left') 14 | bottomLeftContainer.classList.add('saber-toasts-containers') 15 | document.body.append(bottomLeftContainer) 16 | 17 | const topLeftContainer = document.createElement('div') 18 | topLeftContainer.classList.add('saber-toasts-container-top-left') 19 | topLeftContainer.classList.add('saber-toasts-containers') 20 | document.body.append(topLeftContainer) 21 | } 22 | initSaberToast() 23 | 24 | class SaberToast { 25 | constructor() { 26 | this.color = "" 27 | this.icon = "" 28 | this.iconBackground = "" 29 | } 30 | success(params) { 31 | this.color = "#52BF5A" 32 | this.icon = `` 33 | this.iconBackground = "rgba(82, 191, 90, 0.15)" 34 | this.fire(params) 35 | } 36 | error(params) { 37 | this.color = "#F96666" 38 | this.icon = `` 39 | this.iconBackground = "rgba(249, 102, 102, 0.15)" 40 | this.fire(params) 41 | } 42 | warn(params) { 43 | this.color = "#BF9725" 44 | this.icon = `` 45 | this.iconBackground = "rgba(191, 151, 37, 0.15)" 46 | this.fire(params) 47 | } 48 | info(params) { 49 | this.color = "#5953FF" 50 | this.icon = `` 51 | this.iconBackground = "rgba(89, 83, 255, 0.15)" 52 | this.fire(params) 53 | } 54 | fire(params) { 55 | const DEFAULT_RTL = document.querySelector('html').getAttribute('dir')?.toLowerCase() === 'rtl'; 56 | const { title, text, delay, duration, rtl, position } = { title: "", text: "", delay: 200, duration: 2600, rtl: DEFAULT_RTL, position: "bottom-right", ...params } 57 | const div = document.createElement('div') 58 | div.classList.add('saber-toast') 59 | div.style.textAlign = rtl ? "right" : "left" 60 | div.innerHTML = ` 61 | 62 |
63 | 64 | ${this.icon} 65 | 66 |
67 |
68 |

69 | ${title} 70 |

71 |

72 | ${text} 73 |

74 |
75 |
76 | 77 | 78 | 79 | 80 | 81 |
82 | ` 83 | 84 | let isRight 85 | switch (position) { 86 | case "bottom-right": 87 | document.querySelector('.saber-toasts-container-bottom-right').append(div) 88 | isRight = true 89 | break 90 | case "top-right": 91 | document.querySelector('.saber-toasts-container-top-right').append(div) 92 | isRight = true 93 | break 94 | case "bottom-left": 95 | document.querySelector('.saber-toasts-container-bottom-left').append(div) 96 | isRight = false 97 | break 98 | case "top-left": 99 | document.querySelector('.saber-toasts-container-top-left').append(div) 100 | isRight = false 101 | break 102 | default: 103 | document.querySelector('.saber-toasts-container-bottom-right').append(div) 104 | isRight = true 105 | } 106 | 107 | if (isRight) { 108 | div.style.right = "-320px" 109 | } else { 110 | div.style.left = "-320px" 111 | } 112 | 113 | div.style.transitionDuration = `${delay}ms` 114 | setTimeout(() => { 115 | if (isRight) { 116 | div.style.right = "0px" 117 | } else { 118 | div.style.left = "0px" 119 | } 120 | }, 10) 121 | 122 | let mySecondTimeout = setTimeout(() => { 123 | div.style.transitionDuration = `${delay}ms` 124 | if (isRight) { 125 | div.style.right = "-320px" 126 | } else { 127 | div.style.left = "-320px" 128 | } 129 | }, delay + duration) 130 | let myThirdTimeout = setTimeout(() => { 131 | div.remove() 132 | }, 2 * delay + duration) 133 | 134 | div.addEventListener("mouseover", () => { 135 | clearTimeout(mySecondTimeout) 136 | clearTimeout(myThirdTimeout) 137 | }) 138 | div.addEventListener("mouseout", () => { 139 | mySecondTimeout = setTimeout(() => { 140 | div.style.transitionDuration = `${delay}ms` 141 | if (isRight) { 142 | div.style.right = "-320px" 143 | } else { 144 | div.style.left = "-320px" 145 | } 146 | }, delay + duration) 147 | myThirdTimeout = setTimeout(() => { 148 | div.remove() 149 | }, 2 * delay + duration) 150 | }) 151 | 152 | div.querySelector(".close-icon").addEventListener("click", () => { 153 | div.style.transitionDuration = `${delay}ms` 154 | setTimeout(() => { 155 | if (isRight) { 156 | div.style.right = "-320px" 157 | } else { 158 | div.style.left = "-320px" 159 | } 160 | setTimeout(() => { 161 | div.remove() 162 | }, delay) 163 | }, 10) 164 | }) 165 | } 166 | } 167 | 168 | const saberToast = new SaberToast() 169 | --------------------------------------------------------------------------------