Skip to content

Commit 790bc2e

Browse files
tutorialcodeAndy
and
Andy
authored
Add Vue mastery Promotion Banner for Black Friday 2022 (#2074)
Co-authored-by: Andy <[email protected]>
1 parent 0ba4df6 commit 790bc2e

File tree

5 files changed

+356
-0
lines changed

5 files changed

+356
-0
lines changed
Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
<template>
2+
<div id="vm-banner" role="banner" class="vuemastery-banner" v-if="isVisible">
3+
<div class="vuemastery-planet"></div>
4+
<a
5+
href="https://www.vuemastery.com/black-friday/"
6+
target="_blank"
7+
class="vuemastery-banner--link"
8+
><img
9+
src="/images/vuemastery/logo-vuemastery.svg"
10+
alt="vuemastery"
11+
class="vuemastery-banner--logo"
12+
/>
13+
<div class="vuemastery-banner--wrapper">
14+
<p class="text">
15+
<span>Vue Mastery's Black Friday Sale:</span>Save over 50% off a year of Vue courses
16+
</p>
17+
<button class="vuemastery-button">Get discount</button>
18+
</div></a
19+
>
20+
<div class="vuemastery-banner--close" @click.stop.prevent="close"></div>
21+
</div>
22+
</template>
23+
24+
<script setup>
25+
import { ref, onMounted } from 'vue'
26+
const isVisible = ref(false)
27+
onMounted(() => {
28+
isVisible.value = !localStorage.getItem('VM_FW_22_OFFER_NOV')
29+
if (isVisible.value) document.body.classList.add('has-top-banner')
30+
})
31+
function close () {
32+
isVisible.value = false
33+
document.body.classList.remove('has-top-banner')
34+
localStorage.setItem('VM_FW_22_OFFER_NOV', 1)
35+
}
36+
</script>
37+
38+
<style>
39+
.vuemastery-banner {
40+
background: #071532;
41+
overflow: hidden;
42+
position: fixed;
43+
top: 0;
44+
width: 100%;
45+
transition: all 2s cubic-bezier(.34,.06,.01,1);
46+
cursor: pointer;
47+
z-index: var(--vp-z-index-banner);
48+
}
49+
50+
.vuemastery-banner:after,
51+
.vuemastery-banner:before {
52+
content: "";
53+
position: absolute;
54+
pointer-events: none;
55+
transition: all 1s cubic-bezier(.34, .06, .01, 1);
56+
bottom: 0;
57+
}
58+
59+
.vuemastery-banner:after {
60+
width: 100%;
61+
position: absolute;
62+
transition: all 2s cubic-bezier(.34, .06, .01, 1);
63+
background-image: url(/images/vuemastery/background.png);
64+
background-position: 50%;
65+
background-size: 100% auto;
66+
top: 0;
67+
}
68+
69+
.vuemastery-banner:before {
70+
height: 100%;
71+
width: 100%;
72+
}
73+
74+
@media (min-width:1001px) {
75+
76+
.vuemastery-banner:hover:after,
77+
.vuemastery-banner:hover:before {
78+
transition: all 2s cubic-bezier(.34, .06, .01, 1);
79+
}
80+
81+
.vuemastery-banner:hover:before {
82+
transform: translateX(50%);
83+
}
84+
85+
.vuemastery-banner:hover:after {
86+
transform: scale(1.2);
87+
}
88+
89+
.vuemastery-banner:hover .vuemastery-planet {
90+
transform: rotate(-35deg) scale(10) translateX(40%);
91+
}
92+
93+
.vuemastery-banner:hover .vuemastery-planet:after {
94+
transform: translateX(-93px) scale(1.3);
95+
opacity: 0;
96+
}
97+
98+
.vuemastery-banner:hover .vuemastery-banner--close:after,
99+
.vuemastery-banner:hover .vuemastery-banner--close:before {
100+
transform-origin: 100%;
101+
}
102+
103+
.vuemastery-banner:hover .vuemastery-banner--close:hover:after,
104+
.vuemastery-banner:hover .vuemastery-banner--close:hover:before {
105+
transition: transform .2s ease-in .5s, transform-origin .2s ease-in;
106+
transform-origin: 50%;
107+
}
108+
109+
.vuemastery-banner:hover .vuemastery-button:after {
110+
left: 120%;
111+
transition: left 1.5s cubic-bezier(.19, 1, .22, 1);
112+
}
113+
}
114+
115+
.vuemastery-banner--link {
116+
display: flex;
117+
height: 80px;
118+
justify-content: center;
119+
overflow: hidden;
120+
position: relative;
121+
z-index: 2;
122+
}
123+
124+
@media (max-width:770px) {
125+
.vuemastery-banner--link {
126+
justify-content: start;
127+
height: 65px;
128+
}
129+
}
130+
131+
.vuemastery-banner--wrapper {
132+
display: flex;
133+
height: 100%;
134+
align-items: center;
135+
position: relative;
136+
color: #fff;
137+
z-index: 3;
138+
transition: all 2s cubic-bezier(.34, .06, .01, 1);
139+
}
140+
141+
.vuemastery-banner--wrapper p {
142+
margin: -3px 50px 0 20px;
143+
font-size: 1.17rem;
144+
font-weight: 600;
145+
white-space: nowrap;
146+
position: relative;
147+
line-height: 1.7;
148+
}
149+
150+
.vuemastery-banner--wrapper span {
151+
font-size: 1rem;
152+
display: block;
153+
}
154+
155+
@media (max-width:770px) {
156+
.vuemastery-banner--wrapper {
157+
flex-direction: column;
158+
width: calc(100% - 172px);
159+
}
160+
161+
.vuemastery-banner--wrapper p,
162+
.vuemastery-banner--wrapper span {
163+
margin: .5rem 0 0;
164+
font-size: .8rem;
165+
color: #fff;
166+
}
167+
}
168+
169+
@media (max-width:770px) {
170+
.vuemastery-banner--wrapper span {
171+
display: none;
172+
}
173+
}
174+
175+
@media (max-width:330px) {
176+
.vuemastery-banner--wrapper p {
177+
font-size: .6rem;
178+
margin: -3px 28px 0 0;
179+
}
180+
}
181+
182+
.vuemastery-banner--logo {
183+
height: 102%;
184+
margin-top: -1px;
185+
margin-left: -90px;
186+
position: relative;
187+
z-index: 2;
188+
transition: all 2s cubic-bezier(.34, .06, .01, 1);
189+
}
190+
191+
@media (max-width:770px) {
192+
.vuemastery-banner--logo {
193+
margin-left: -40px;
194+
transform: rotateY(190deg);
195+
height: 105%;
196+
}
197+
}
198+
199+
.vuemastery-banner--close {
200+
height: 100%;
201+
width: 75px;
202+
position: absolute;
203+
top: 0;
204+
right: 0;
205+
z-index: 2;
206+
-webkit-tap-highlight-color: transparent;
207+
cursor: pointer;
208+
}
209+
210+
.vuemastery-banner--close:after,
211+
.vuemastery-banner--close:before {
212+
content: "";
213+
width: 25px;
214+
height: 2px;
215+
position: absolute;
216+
top: 39px;
217+
right: 25px;
218+
background-color: #fff;
219+
transform-origin: 50%;
220+
transform: rotate(-45deg);
221+
transition: all .2s ease-out;
222+
}
223+
224+
.vuemastery-banner--close:after {
225+
transform: rotate(45deg);
226+
}
227+
228+
.vuemastery-banner--close:hover:after,
229+
.vuemastery-banner--close:hover:before {
230+
transform: rotate(180deg);
231+
}
232+
233+
@media (max-width:770px) {
234+
235+
.vuemastery-banner--close:after,
236+
.vuemastery-banner--close:before {
237+
width: 15px;
238+
top: 19px;
239+
right: 14px;
240+
}
241+
}
242+
243+
.vuemastery-promo .navbar {
244+
position: relative;
245+
}
246+
247+
.vuemastery-promo .sidebar {
248+
position: absolute;
249+
top: 7.60625rem;
250+
}
251+
252+
.vuemastery-planet {
253+
position: absolute;
254+
z-index: 2;
255+
width: 100%;
256+
height: 100%;
257+
transform-origin: bottom right;
258+
transition: all 2s cubic-bezier(.34, .06, .01, 1);
259+
}
260+
261+
@media (max-width:770px) {
262+
.vuemastery-planet {
263+
transform: translateX(70px);
264+
}
265+
}
266+
267+
.vuemastery-planet:after,
268+
.vuemastery-planet:before {
269+
content: "";
270+
position: absolute;
271+
pointer-events: none;
272+
bottom: 0;
273+
width: 100%;
274+
top: 0;
275+
right: 0;
276+
background-image: url(/images/vuemastery/black-hole.png);
277+
background-attachment: fixed;
278+
background-size: auto 200px;
279+
background-position: top -52px right -24px;
280+
background-repeat: no-repeat;
281+
}
282+
283+
@media (max-width:770px) {
284+
.vuemastery-planet:before {
285+
background-size: auto 200px;
286+
background-position: top -81px right -82px;
287+
}
288+
}
289+
290+
.vuemastery-planet:after {
291+
background-image: url(/images/vuemastery/planets.png);
292+
transition: all 3s cubic-bezier(.34, .06, .01, 1);
293+
background-position: left -80px top -80px;
294+
background-size: auto 180px;
295+
}
296+
297+
@media (max-width:770px) {
298+
.vuemastery-planet:after {
299+
display: none;
300+
}
301+
}
302+
303+
@media print {
304+
.vuemastery-banner {
305+
display: none;
306+
}
307+
}
308+
309+
.vuemastery-button {
310+
display: inline-flex;
311+
background: linear-gradient(to top right, #3d2c61, #835ec2);
312+
height: 38px;
313+
margin: .5em 0;
314+
line-height: 38px;
315+
padding: 0 30px;
316+
color: #fff;
317+
text-decoration: none;
318+
align-items: center;
319+
justify-content: center;
320+
outline: 0;
321+
text-transform: uppercase;
322+
border: none;
323+
border-radius: 36px;
324+
font-weight: 700;
325+
font-size: 12px;
326+
cursor: pointer;
327+
position: relative;
328+
overflow: hidden;
329+
}
330+
331+
.vuemastery-button:after,
332+
.vuemastery-button:before {
333+
background: linear-gradient(to top right, transparent, #fff);
334+
content: "";
335+
height: 150px;
336+
left: -175px;
337+
opacity: .1;
338+
position: absolute;
339+
top: -50px;
340+
transform: rotate(35deg);
341+
width: 100px;
342+
}
343+
344+
.has-top-banner {
345+
--vt-banner-height: 80px;
346+
}
347+
.has-top-banner .banner {
348+
height: 24px;
349+
line-height: 24px;
350+
top: 80px;
351+
}
352+
</style>

.vitepress/theme/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@ import SponsorsAside from './components/SponsorsAside.vue'
1111
import VueJobs from './components/VueJobs.vue'
1212
import VueSchoolLink from './components/VueSchoolLink.vue'
1313
// import Banner from './components/Banner.vue'
14+
import VueMasteryBanner from './components/VueMasteryBanner.vue'
1415

1516
export default Object.assign({}, VPTheme, {
1617
Layout: () => {
1718
// @ts-ignore
1819
return h(VPTheme.Layout, null, {
1920
// banner: () => h(Banner),
21+
banner: () => h('div', {}, [
22+
h(VueMasteryBanner)
23+
]),
2024
'sidebar-top': () => h(PreferenceSwitch),
2125
'aside-mid': () => h(SponsorsAside)
2226
})
53.4 KB
Loading
269 KB
Loading
40.1 KB
Loading

0 commit comments

Comments
 (0)