Skip to content

Commit be15e4c

Browse files
committed
docs: add XMas banner
1 parent 1372d1b commit be15e4c

File tree

5 files changed

+321
-1
lines changed

5 files changed

+321
-1
lines changed

docs/assets/js/snowflakes.js

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Shim for requestAnimationFrame with setTimeout fallback
2+
const requestAnimFrame =
3+
window.requestAnimationFrame ||
4+
window.webkitRequestAnimationFrame ||
5+
window.mozRequestAnimationFrame ||
6+
function (callback) {
7+
return window.setTimeout(callback, 1000 / 60)
8+
}
9+
10+
// Snowflake class
11+
class Snowflake {
12+
constructor(width, height) {
13+
this.width = width
14+
this.height = height
15+
this.reset()
16+
}
17+
18+
// Reset snowflake to a new random position and velocity
19+
reset() {
20+
this.x = Math.random() * this.width
21+
this.y = Math.random() * -this.height
22+
this.vy = 1 + (Math.random() * 3)
23+
this.vx = 0.5 - Math.random()
24+
this.r = 1 + (Math.random() * 2)
25+
this.o = 0.5 + (Math.random() * 0.5)
26+
}
27+
28+
// Move the snowflake
29+
updatePosition() {
30+
this.y += this.vy
31+
this.x += this.vx
32+
}
33+
34+
// Check if the snowflake has moved beyond the bottom
35+
isOutOfView() {
36+
return this.y > this.height
37+
}
38+
}
39+
40+
// Main function to create snowfall
41+
const snowflakes = (target, count = 200) => {
42+
// Determine if the target is a selector string or a DOM element
43+
const container = typeof target === 'string' ? document.querySelector(target) : target
44+
45+
if (!container) {
46+
return
47+
}
48+
49+
// Create and configure canvas
50+
const canvas = document.createElement('canvas')
51+
const ctx = canvas.getContext('2d')
52+
53+
let width = container.clientWidth
54+
let height = container.clientHeight
55+
let active = false
56+
57+
// Initialize canvas styles
58+
canvas.style.position = 'absolute'
59+
canvas.style.left = '0'
60+
canvas.style.top = '0'
61+
canvas.style.pointerEvents = 'none' // Allows clicks to pass through
62+
63+
// Snowflake instances
64+
const flakes = []
65+
66+
// Create snowflakes
67+
for (let i = 0; i < count; i++) {
68+
flakes.push(new Snowflake(width, height))
69+
}
70+
71+
// Handle canvas resizing
72+
const onResize = () => {
73+
width = container.clientWidth
74+
height = container.clientHeight
75+
76+
canvas.width = width
77+
canvas.height = height
78+
ctx.fillStyle = '#fff'
79+
80+
// Reactivate animation only if width > 600
81+
const wasActive = active
82+
active = width > 600
83+
84+
// If animation was inactive but is now active, request next frame
85+
if (!wasActive && active) {
86+
requestAnimFrame(update)
87+
}
88+
}
89+
90+
// Animation loop
91+
const update = () => {
92+
// Clear the canvas
93+
ctx.clearRect(0, 0, width, height)
94+
95+
// Stop updating if not active
96+
if (!active) {
97+
return
98+
}
99+
100+
// Update and draw each snowflake
101+
flakes.forEach(flake => {
102+
flake.updatePosition()
103+
104+
ctx.globalAlpha = flake.o
105+
ctx.beginPath()
106+
ctx.arc(flake.x, flake.y, flake.r, 0, Math.PI * 2)
107+
ctx.closePath()
108+
ctx.fill()
109+
110+
// If out of view, reset the flake
111+
if (flake.isOutOfView()) {
112+
flake.reset()
113+
}
114+
})
115+
116+
requestAnimFrame(update)
117+
}
118+
119+
// Initial setup
120+
onResize()
121+
window.addEventListener('resize', onResize, false)
122+
container.append(canvas)
123+
}
124+
125+
if (document.querySelector('.banner-xmas')) {
126+
snowflakes('.banner-xmas', 200)
127+
}

docs/layouts/_default/docs.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<main class="docs-main order-1">
44
<div class="docs-intro ps-lg-4">
55
{{ partial "breadcrumb" . }}
6-
{{ partial "banner-black-friday" . }}
6+
{{ partial "banner-xmas" . }}
77
{{ partial "banner" . }}
88
{{ if .Page.Params.bootstrap }}
99
<div class="d-flex flex-column">
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<section
2+
class="banner-xmas position-relative text-white rounded p-3 p-xl-4 ps-xl-0 mb-5"
3+
style="background-color: rgb(204, 35, 30)"
4+
>
5+
<div class="container">
6+
<div class="row flex-column flex-md-row align-items-md-center">
7+
<div class="col-auto d-none d-lg-flex">
8+
<img
9+
src="https://coreui.io/bootstrap/docs/assets/img/christmas-tree.svg"
10+
alt="Christmas Tree"
11+
height="140"
12+
width="140"
13+
style="transform: rotate(-5deg)"
14+
/>
15+
</div>
16+
<div class="col">
17+
<div class="fw-semibold fs-4">Merry Christmas &amp; Happy New Year</div>
18+
<div>
19+
Extra 25% off for all sale items + Free CoreUI Icons PRO with every
20+
order!<br />Limited offer ends 1st January 2025, use code
21+
<strong>2024XMAS25</strong> during checkout.
22+
</div>
23+
</div>
24+
<div class="col-auto">
25+
<a
26+
href="https://coreui.io/pricing/#pricing-table"
27+
class="btn border-2 btn-outline-light btn-lg mt-3 mt-lg-0"
28+
>Get offer!</a
29+
>
30+
</div>
31+
</div>
32+
</div>
33+
<canvas
34+
width="974"
35+
height="188"
36+
style="position: absolute; left: 0px; top: 0px; pointer-events: none"
37+
></canvas>
38+
</section>

docs/layouts/partials/scripts.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,6 @@
3030
{{- $esbuildOptions = merge $esbuildOptions (dict "params" $esbuildParams) -}}
3131
{{- $searchJs := resources.Get "js/search.js" | js.Build $esbuildOptions | resources.Copy "/assets/js/search.js" }}
3232
<script defer src="{{ $searchJs.Permalink }}"></script>
33+
34+
{{- $snowflakesJs := resources.Get "js/snowflakes.js" | js.Build $esbuildOptions | resources.Copy "/assets/js/snowflakes.js" }}
35+
<script defer src="{{ $snowflakesJs.Permalink }}"></script>
Lines changed: 152 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)