Skip to content

Commit 702ea55

Browse files
Mazizovaclaude
andauthored
Add DuckDB × MySQL Day announcement pop-up (#190)
Slides in at the bottom left after 10 seconds on any page except the event page, links to the event, stays dismissed for a week, and disappears after the event date. Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
1 parent f9d7f4d commit 702ea55

4 files changed

Lines changed: 179 additions & 0 deletions

File tree

‎assets/scss/_event-popup.scss‎

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// ── Event announcement pop-up (bottom left) ─────────────────────────────────
2+
3+
.ev-popup {
4+
position: fixed;
5+
left: 20px;
6+
bottom: 20px;
7+
z-index: 90;
8+
width: #{"min(360px, calc(100vw - 40px))"};
9+
background: $dark-card;
10+
border: 1px solid $dark-border;
11+
border-radius: 14px;
12+
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.5);
13+
overflow: hidden;
14+
opacity: 0;
15+
transform: translateY(18px);
16+
transition: opacity 0.35s ease, transform 0.35s ease;
17+
18+
&.is-visible {
19+
opacity: 1;
20+
transform: none;
21+
}
22+
23+
@media (prefers-reduced-motion: reduce) {
24+
transition: none;
25+
}
26+
27+
@media print {
28+
display: none;
29+
}
30+
}
31+
32+
.ev-popup-link {
33+
display: block;
34+
color: inherit;
35+
text-decoration: none;
36+
37+
&:hover .ev-popup-cta { text-decoration: underline; }
38+
&:focus-visible { outline: 2px solid $accent; outline-offset: -2px; }
39+
}
40+
41+
.ev-popup-img {
42+
display: block;
43+
width: 100%;
44+
height: auto;
45+
aspect-ratio: 1730 / 909;
46+
object-fit: cover;
47+
background: $dark-surface;
48+
}
49+
50+
.ev-popup-body {
51+
display: flex;
52+
flex-direction: column;
53+
gap: 6px;
54+
padding: 14px 18px 16px;
55+
}
56+
57+
.ev-popup-kicker {
58+
font-size: 11px;
59+
font-weight: 700;
60+
letter-spacing: 0.1em;
61+
text-transform: uppercase;
62+
color: $accent;
63+
}
64+
65+
.ev-popup-title {
66+
font-size: 18px;
67+
font-weight: 700;
68+
line-height: 1.25;
69+
color: $white;
70+
}
71+
72+
.ev-popup-text {
73+
font-size: 14px;
74+
line-height: 1.45;
75+
color: $off-white;
76+
opacity: 0.8;
77+
}
78+
79+
.ev-popup-cta {
80+
margin-top: 4px;
81+
font-size: 14px;
82+
font-weight: 600;
83+
color: $accent;
84+
}
85+
86+
.ev-popup-close {
87+
position: absolute;
88+
top: 8px;
89+
right: 8px;
90+
z-index: 1;
91+
width: 30px;
92+
height: 30px;
93+
display: flex;
94+
align-items: center;
95+
justify-content: center;
96+
padding: 0;
97+
border: 0;
98+
border-radius: 50%;
99+
background: rgba(10, 12, 24, 0.7);
100+
color: #fff;
101+
font-size: 20px;
102+
line-height: 1;
103+
cursor: pointer;
104+
105+
&:hover { background: rgba(10, 12, 24, 0.95); }
106+
&:focus-visible { outline: 2px solid $accent; outline-offset: 2px; }
107+
}
108+
109+
[data-theme="light"] {
110+
.ev-popup {
111+
background: #ffffff;
112+
border-color: #dde3ed;
113+
box-shadow: 0 18px 48px rgba(15, 23, 42, 0.18);
114+
}
115+
.ev-popup-kicker, .ev-popup-cta { color: #0077a8; }
116+
.ev-popup-title { color: #0f172a; }
117+
.ev-popup-text { color: #334155; opacity: 1; }
118+
}
119+
120+
@media (max-width: 576px) {
121+
.ev-popup { left: 12px; bottom: 12px; width: #{"calc(100vw - 24px)"}; }
122+
.ev-popup-img { display: none; }
123+
.ev-popup-body { padding-right: 44px; }
124+
}

‎assets/scss/main.scss‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ img {
4545
@import "showcase";
4646
@import "image-view";
4747
@import "footer";
48+
@import "event-popup";
4849
@import "light-theme";
4950

5051
// Page content (about, etc.)

‎layouts/_default/baseof.html‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
{{ block "main" . }}{{ end }}
1818
</main>
1919
{{ partial "footer.html" . }}
20+
{{ partial "event-popup.html" . }}
2021
<script>
2122
(function () {
2223
// Theme toggle

‎layouts/partials/event-popup.html‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{{/* Announcement pop-up for the featured event (DuckDB × MySQL Day). Slides in at
2+
the bottom left of any page after 10 seconds, links to the event page, and
3+
stays dismissed for a week once closed or clicked. Not rendered on the event
4+
page itself or once the event date has passed. Text comes from the event
5+
page's front matter; timing and dismissal live in the inline script. */}}
6+
{{ $ev := site.GetPage "/events/duckdb-mysql-day" }}
7+
{{ if and $ev (now.Before ($ev.Date.AddDate 0 0 1)) (ne $.RelPermalink $ev.RelPermalink) }}
8+
{{ $cover := $ev.Resources.GetMatch "cover.jpg" }}
9+
<aside class="ev-popup" id="event-popup" hidden aria-label="Event announcement" data-id="duckdb-mysql-day" data-end="{{ $ev.Date.AddDate 0 0 1 | time.Format "2006-01-02T00:00:00Z" }}">
10+
<button type="button" class="ev-popup-close" aria-label="Close announcement">&times;</button>
11+
<a href="{{ $ev.RelPermalink }}" class="ev-popup-link">
12+
{{ with $cover }}{{ $img := .Resize "640x q80" }}<img src="{{ $img.RelPermalink }}" width="{{ $img.Width }}" height="{{ $img.Height }}" alt="" class="ev-popup-img" loading="lazy">{{ end }}
13+
<span class="ev-popup-body">
14+
<span class="ev-popup-kicker">{{ $ev.Date.Format "January 2" }} · {{ with $ev.Params.home_meta }}{{ . }}{{ else }}Online{{ end }}</span>
15+
<span class="ev-popup-title">{{ $ev.Title }}</span>
16+
<span class="ev-popup-text">A one-day online conference on fast analytics for MySQL.</span>
17+
<span class="ev-popup-cta">See the speakers &amp; register →</span>
18+
</span>
19+
</a>
20+
</aside>
21+
<script>
22+
(function () {
23+
var el = document.getElementById('event-popup');
24+
if (!el) return;
25+
var key = 'ev-popup-dismissed-' + el.getAttribute('data-id');
26+
var week = 7 * 24 * 60 * 60 * 1000;
27+
try {
28+
var t = parseInt(localStorage.getItem(key), 10);
29+
if (t && Date.now() - t < week) return;
30+
} catch (e) {}
31+
var end = Date.parse(el.getAttribute('data-end'));
32+
if (end && Date.now() > end) return;
33+
34+
function dismiss() {
35+
try { localStorage.setItem(key, String(Date.now())); } catch (e) {}
36+
el.classList.remove('is-visible');
37+
setTimeout(function () { el.hidden = true; }, 400);
38+
}
39+
el.querySelector('.ev-popup-close').addEventListener('click', dismiss);
40+
el.querySelector('.ev-popup-link').addEventListener('click', function () {
41+
try { localStorage.setItem(key, String(Date.now())); } catch (e) {}
42+
});
43+
el.addEventListener('keydown', function (e) { if (e.key === 'Escape') dismiss(); });
44+
45+
setTimeout(function () {
46+
el.hidden = false;
47+
requestAnimationFrame(function () {
48+
requestAnimationFrame(function () { el.classList.add('is-visible'); });
49+
});
50+
}, 10000);
51+
})();
52+
</script>
53+
{{ end }}

0 commit comments

Comments
 (0)