1
+ <template >
2
+ <div
3
+ :class =" vueMasteryClass"
4
+ class =" vuemastery-banner-wrapper"
5
+ ref =" $vueMasteryBanner"
6
+ role =" banner"
7
+ v-if =" isVisible"
8
+ >
9
+ <a
10
+ id =" vm-pinia-weekend"
11
+ href =" https://www.vuemastery.com/pinia"
12
+ target =" _blank"
13
+ >
14
+ <img
15
+ id =" vm-logo-full"
16
+ src =" /vuemastery/vuemastery-white.svg"
17
+ alt =" vuemastery"
18
+ />
19
+ <img
20
+ id =" vm-logo-small"
21
+ src =" https://firebasestorage.googleapis.com/v0/b/vue-mastery.appspot.com/o/flamelink%2Fmedia%2Fvue-mastery-logo-small.png?alt=media&token=941fcc3a-2b6f-40e9-b4c8-56b3890da108"
22
+ alt =" vuemastery"
23
+ />
24
+ <div class =" vm-pinia-weekend-wrapper" >
25
+ <div class =" vm-pinia-weekend-content" >
26
+ <h1 class =" vm-pinia-weekend-title" >
27
+ PINIA WEEKEND <span >MARCH 24-26</span >
28
+ </h1 >
29
+ <p class =" vm-pinia-weekend-sub" >
30
+ Watch all 4 premium courses for free
31
+ </p >
32
+ </div >
33
+ <button id =" vm-banner-cta" >Secure your spot</button >
34
+ </div >
35
+ <button id =" vm-banner-close" @click.prevent =" closeBanner" >X</button >
36
+ </a >
37
+ </div >
38
+ </template >
39
+
40
+ <script setup lang="ts">
41
+ import { ref , onMounted , computed , nextTick } from ' vue'
42
+
43
+ const isVisible = ref <Boolean >(true )
44
+ const isMenuFixed = ref <Boolean >(false )
45
+ const $vueMasteryBanner = ref <HTMLElement | null >(null )
46
+
47
+ const nameStorage = ' VUEMASTERY-BANNER--PINIA-WEEKEND-MARCH-2023'
48
+
49
+ const getMenuPosition = () => {
50
+ return $vueMasteryBanner .value ?.clientHeight || 0
51
+ }
52
+
53
+ const isUnderBanner = () => {
54
+ return window .pageYOffset > getMenuPosition ()
55
+ }
56
+
57
+ const fixMenuAfterBanner = () => {
58
+ if (isUnderBanner ()) {
59
+ if (! isMenuFixed .value ) {
60
+ // The menu will be fixed
61
+ isMenuFixed .value = true
62
+ }
63
+ } else if (isMenuFixed .value ) {
64
+ // The menu stay under the banner
65
+ isMenuFixed .value = false
66
+ }
67
+ }
68
+
69
+ const toggleBannerEvents = (on : Boolean ) => {
70
+ // Add or remove event listerners attached to the DOM
71
+ let method: ' addEventListener' | ' removeEventListener' = on
72
+ ? ' addEventListener'
73
+ : ' removeEventListener'
74
+ window [method ](' resize' , getMenuPosition )
75
+ window [method ](' scroll' , fixMenuAfterBanner )
76
+ }
77
+
78
+ const closeBanner = () => {
79
+ console .log (' closeBanner => ' )
80
+ // Remove events
81
+ toggleBannerEvents (false )
82
+ // Hide the banner
83
+ isVisible .value = false
84
+ // Save action in the local storage
85
+ localStorage .setItem (nameStorage , String (true ))
86
+ }
87
+
88
+ const initBanner = () => {
89
+ // Add event listeners
90
+ toggleBannerEvents (true )
91
+ // Get the menu position
92
+ getMenuPosition ()
93
+ // Check current page offset position
94
+ isMenuFixed .value = isUnderBanner ()
95
+ }
96
+
97
+ const vueMasteryClass = computed (() => {
98
+ return {
99
+ ' vuemastery-menu-fixed' : ! isMenuFixed .value ,
100
+ }
101
+ })
102
+
103
+ onMounted (() => {
104
+ isVisible .value = ! localStorage .getItem (nameStorage )
105
+ if (isVisible .value ) {
106
+ nextTick (initBanner )
107
+ }
108
+ })
109
+ </script >
110
+ <style scoped>
111
+ .vuemastery-banner-wrapper {
112
+ position : relative ;
113
+ top : 0 ;
114
+ bottom : 0 ;
115
+ left : 0 ;
116
+ right : 0 ;
117
+ z-index : 60 ;
118
+ width : 100% ;
119
+ height : 100% ;
120
+ max-height : 70px ;
121
+ background : url (/vuemastery/background-vuemastery.svg ) left center no-repeat ;
122
+ overflow : hidden ;
123
+ padding : 12px ;
124
+ margin : 0 ;
125
+ background-size : cover ;
126
+ }
127
+ .vuemastery-banner-wrapper :before {
128
+ content : ' ' ;
129
+ background : url (/vuemastery/background-bubbles-vuemastery.svg ) left center
130
+ no-repeat ;
131
+ background-size : cover ;
132
+ position : absolute ;
133
+ top : 0 ;
134
+ bottom : 0 ;
135
+ left : 0 ;
136
+ right : 0 ;
137
+ transition : all 0.3s ease-out 0.1s ;
138
+ transform : scale (1.1 );
139
+ width : 100% ;
140
+ height : 100% ;
141
+ }
142
+
143
+ .vuemastery-banner-wrapper :after {
144
+ content : ' ' ;
145
+ background : url (/vuemastery/lock-vuemastery.svg ) right center no-repeat ;
146
+ background-size : auto 100% ;
147
+ position : absolute ;
148
+ width : 100% ;
149
+ height : 100% ;
150
+ top : 0 ;
151
+ left : 0 ;
152
+ pointer-events : none ;
153
+ }
154
+
155
+ .vuemastery-banner-wrapper :hover {
156
+ background-size : 150% auto ;
157
+ }
158
+ .vuemastery-banner-wrapper :hover :before {
159
+ transform : scale (1 );
160
+ }
161
+ .vuemastery-banner-wrapper :hover :after {
162
+ background-image : url (/vuemastery/unlock-vuemastery.svg );
163
+ }
164
+
165
+ #vm-pinia-weekend {
166
+ position : relative ;
167
+ width : 100% ;
168
+ height : 100% ;
169
+ text-decoration : none ;
170
+ color : white ;
171
+ display : flex ;
172
+ justify-content : center ;
173
+ align-items : center ;
174
+ overflow : hidden ;
175
+ }
176
+
177
+ #vm-logo-full {
178
+ position : absolute ;
179
+ left : 15px ;
180
+ width : 120px ;
181
+ }
182
+
183
+ #vm-logo-small {
184
+ display : none ;
185
+ }
186
+
187
+ #vm-banner-close {
188
+ position : absolute ;
189
+ right : 12px ;
190
+ color : #fff ;
191
+ font-size : 20px ;
192
+ font-weight : bold ;
193
+ display : flex ;
194
+ align-items : center ;
195
+ justify-content : center ;
196
+ }
197
+ #vm-banner-close :hover {
198
+ color : #9d9c9c ;
199
+ }
200
+
201
+ .vm-pinia-weekend-wrapper {
202
+ display : flex ;
203
+ align-items : center ;
204
+ }
205
+
206
+ .vm-pinia-weekend-title {
207
+ margin : 0 ;
208
+ padding : 0 ;
209
+ font-weight : bold ;
210
+ font-size : 16px ;
211
+ text-align : center ;
212
+ background : linear-gradient (145deg , #c3ffac , #86ec87 , #38a56a );
213
+ background-clip : text ;
214
+ -webkit-background-clip : text ;
215
+ -webkit-text-fill-color : transparent ;
216
+ }
217
+ .vm-pinia-weekend-sub {
218
+ margin : 0 ;
219
+ padding : 0 ;
220
+ font-size : 14px ;
221
+ text-align : center ;
222
+ color : #fff ;
223
+ }
224
+
225
+ #vm-banner-cta {
226
+ position : relative ;
227
+ margin-left : 10px ;
228
+ padding : 12px ;
229
+ background : linear-gradient (to top right , #41b782 , #86d169 );
230
+ border : none ;
231
+ border-radius : 30px ;
232
+ color : #fff ;
233
+ font-size : 12px ;
234
+ font-weight : bold ;
235
+ text-decoration : none ;
236
+ text-transform : uppercase ;
237
+ box-shadow : 0px 17px 10px -10px rgba (0 , 0 , 0 , 0.4 );
238
+ }
239
+ #vm-banner-cta :hover {
240
+ background : linear-gradient (to bottom right , #41b782 , #86d169 );
241
+ }
242
+
243
+ @media (max-width : 850px ) {
244
+ .vuemastery-banner-wrapper :after {
245
+ background : none ;
246
+ }
247
+ }
248
+
249
+ @media (max-width : 767px ) {
250
+ #vm-logo-full {
251
+ left : 10px ;
252
+ width : 100px ;
253
+ }
254
+ #vm-banner-cta {
255
+ display : none ;
256
+ }
257
+ }
258
+
259
+ @media (max-width : 767px ) {
260
+ #vm-logo-full {
261
+ display : none ;
262
+ }
263
+ #vm-logo-small {
264
+ position : absolute ;
265
+ display : block ;
266
+ left : 10px ;
267
+ width : 40px ;
268
+ }
269
+ .vm-pinia-weekend-title {
270
+ font-size : 14px ;
271
+ }
272
+ .vm-pinia-weekend-sub {
273
+ font-size : 12px ;
274
+ }
275
+ }
276
+ </style >
277
+
278
+ <style >
279
+ .Layout :has (.vuemastery-menu-fixed ) > .VPNav {
280
+ position : relative ;
281
+ }
282
+
283
+ .Layout :has (.vuemastery-menu-fixed ) > .VPSidebar {
284
+ margin-top : 4em ;
285
+ }
286
+ </style >
0 commit comments