Skip to content

Commit 0b8424d

Browse files
committed
feat: enhance announcement banner with close button and visibility toggle
1 parent 0294751 commit 0b8424d

File tree

2 files changed

+85
-5
lines changed

2 files changed

+85
-5
lines changed

client/components/announcementBanner/index.js

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,15 @@ export default function AnnouncementBanner() {
3737
const $subtitle = <span className='announcement-banner__subtitle' />;
3838
const $ctaText = <span className='announcement-banner__cta-text' />;
3939

40+
const $closeBtn = (
41+
<button type='button' className='announcement-banner__close' aria-label='Close announcement'>
42+
<span className='icon clear' />
43+
</button>
44+
);
45+
4046
const $link = (
4147
// biome-ignore lint/a11y/useValidAnchor: URL is dynamic
42-
<a target='_blank' rel='noopener noreferrer' className='announcement-banner'>
48+
<a target='_blank' rel='noopener noreferrer' data-visible='true' className='announcement-banner'>
4349
<div className='announcement-banner__content'>
4450
<div className='announcement-banner__logo-wrapper'>{$logo}</div>
4551
<div className='announcement-banner__text'>
@@ -57,9 +63,42 @@ export default function AnnouncementBanner() {
5763
<span className={`announcement-banner__indicator ${index === 0 ? 'active' : ''}`} data-index={index} />
5864
))}
5965
</div>
66+
{$closeBtn}
6067
</a>
6168
);
6269

70+
let intervalId;
71+
72+
const updateHeaderTop = (bannerVisible) => {
73+
const header = document.getElementById('main-header');
74+
if (header) {
75+
if (bannerVisible) {
76+
const bannerHeight = $link.offsetHeight;
77+
header.style.top = `${bannerHeight}px`;
78+
} else {
79+
header.style.top = '0';
80+
}
81+
}
82+
};
83+
84+
$closeBtn.addEventListener('click', (e) => {
85+
e.preventDefault();
86+
e.stopPropagation();
87+
$link.classList.add('hidden');
88+
clearInterval(intervalId);
89+
sessionStorage.setItem('announcement-banner-closed', 'true');
90+
updateHeaderTop(false);
91+
$link.removeAttribute('data-visible');
92+
});
93+
94+
// Check if banner was closed in this session
95+
if (sessionStorage.getItem('announcement-banner-closed') === 'true') {
96+
$link.classList.add('hidden');
97+
} else {
98+
// Set header top after banner is rendered
99+
requestAnimationFrame(() => updateHeaderTop(true));
100+
}
101+
63102
const $content = $link.querySelector('.announcement-banner__content');
64103

65104
const updateBanner = (index, animate = false) => {
@@ -105,7 +144,7 @@ export default function AnnouncementBanner() {
105144
updateBanner(0);
106145

107146
// Toggle banners periodically
108-
setInterval(() => {
147+
intervalId = setInterval(() => {
109148
currentIndex = (currentIndex + 1) % BANNERS.length;
110149
updateBanner(currentIndex, true);
111150
}, TOGGLE_INTERVAL);

client/components/announcementBanner/style.scss

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
.announcement-banner {
2-
z-index: 9;
2+
z-index: 100;
33
margin: 0;
44
display: flex;
55
align-items: center;
66
justify-content: center;
7-
position: relative;
7+
position: sticky;
8+
top: 0;
89
width: 100%;
9-
padding: 12px 20px;
10+
padding: 12px 50px 12px 20px;
1011
box-sizing: border-box;
1112
background: linear-gradient(135deg,
1213
#1a1a2e 0%,
@@ -21,6 +22,10 @@
2122
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
2223
transition: background 0.5s ease, background-size 0.3s ease;
2324

25+
&[data-visible='true']+header {
26+
top: 60px;
27+
}
28+
2429
// Hanging Piece theme - chess-inspired dark green
2530
&--hangingpiece {
2631
background: linear-gradient(135deg,
@@ -74,6 +79,42 @@
7479
display: none;
7580
}
7681

82+
&__close {
83+
position: absolute;
84+
right: 12px;
85+
top: 0;
86+
bottom: 0;
87+
margin: auto;
88+
display: flex;
89+
align-items: center;
90+
justify-content: center;
91+
width: 28px;
92+
height: 28px;
93+
background: rgba(255, 255, 255, 0.1);
94+
border: none;
95+
border-radius: 50%;
96+
cursor: pointer;
97+
transition: all 0.3s ease;
98+
z-index: 2;
99+
padding: 0;
100+
101+
.icon {
102+
color: rgba(255, 255, 255, 0.7);
103+
font-size: 0.9rem;
104+
display: flex;
105+
align-items: center;
106+
justify-content: center;
107+
}
108+
109+
&:hover {
110+
background: rgba(255, 255, 255, 0.2);
111+
112+
.icon {
113+
color: #fff;
114+
}
115+
}
116+
}
117+
77118
@keyframes gradientShift {
78119
0% {
79120
background-position: 0% 50%;

0 commit comments

Comments
 (0)