Skip to content

Commit 76499f8

Browse files
Add Framna announcement popup
- Shows after page fully loads (500ms delay after load event) - Once per session (sessionStorage) - Production: shows from 18.03.2026 - Staging: shows immediately (GATSBY_ACTIVE_ENV=staging) - "Visit Framna" button → https://framna.com/ - All browser APIs guarded in useEffect (no Gatsby SSR crash) Closes #5423 Co-authored-by: Piotr Mionskowski <miensol@users.noreply.github.com>
1 parent a740a66 commit 76499f8

File tree

2 files changed

+176
-0
lines changed

2 files changed

+176
-0
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import React, { useEffect, useState } from 'react'
2+
3+
const SESSION_KEY = 'framna_announcement_shown'
4+
5+
function shouldShowPopup(): boolean {
6+
if (typeof window === 'undefined') return false
7+
8+
const alreadyShown = window.sessionStorage.getItem(SESSION_KEY)
9+
if (alreadyShown) return false
10+
11+
const isStaging = process.env.GATSBY_ACTIVE_ENV === 'staging'
12+
if (isStaging) return true
13+
14+
const showFrom = new Date('2026-03-18T00:00:00')
15+
return new Date() >= showFrom
16+
}
17+
18+
const FramnaAnnouncementPopup: React.FC = () => {
19+
const [visible, setVisible] = useState(false)
20+
21+
useEffect(() => {
22+
const show = () => {
23+
if (shouldShowPopup()) {
24+
setVisible(true)
25+
window.sessionStorage.setItem(SESSION_KEY, '1')
26+
}
27+
}
28+
29+
if (document.readyState === 'complete') {
30+
const timer = setTimeout(show, 500)
31+
return () => clearTimeout(timer)
32+
} else {
33+
const onLoad = () => {
34+
const timer = setTimeout(show, 500)
35+
window.addEventListener('unload', () => clearTimeout(timer), { once: true })
36+
}
37+
window.addEventListener('load', onLoad, { once: true })
38+
return () => window.removeEventListener('load', onLoad)
39+
}
40+
}, [])
41+
42+
if (!visible) return null
43+
44+
const close = () => setVisible(false)
45+
46+
return (
47+
<div
48+
style={{
49+
position: 'fixed',
50+
inset: 0,
51+
backgroundColor: 'rgba(0,0,0,0.5)',
52+
display: 'flex',
53+
alignItems: 'center',
54+
justifyContent: 'center',
55+
zIndex: 9999,
56+
padding: '1rem',
57+
}}
58+
onClick={close}
59+
>
60+
<div
61+
style={{
62+
display: 'flex',
63+
borderRadius: '1rem',
64+
overflow: 'hidden',
65+
maxWidth: '56rem',
66+
width: '100%',
67+
boxShadow: '0 20px 60px rgba(0,0,0,0.3)',
68+
}}
69+
onClick={(e) => e.stopPropagation()}
70+
>
71+
{/* Left green panel */}
72+
<div
73+
style={{
74+
backgroundColor: '#5EE03A',
75+
flex: '0 0 45%',
76+
display: 'flex',
77+
alignItems: 'center',
78+
justifyContent: 'center',
79+
padding: '3rem 2rem',
80+
minHeight: '22rem',
81+
}}
82+
>
83+
<img
84+
src='/images/why-us/timeline/framna.svg'
85+
alt='framna'
86+
style={{ width: '100%', maxWidth: '14rem' }}
87+
/>
88+
</div>
89+
90+
{/* Right white panel */}
91+
<div
92+
style={{
93+
backgroundColor: '#ffffff',
94+
flex: 1,
95+
padding: '3rem 2.5rem',
96+
position: 'relative',
97+
display: 'flex',
98+
flexDirection: 'column',
99+
justifyContent: 'center',
100+
}}
101+
>
102+
{/* Close button */}
103+
<button
104+
onClick={close}
105+
aria-label='Close'
106+
style={{
107+
position: 'absolute',
108+
top: '1.25rem',
109+
right: '1.25rem',
110+
background: 'none',
111+
border: 'none',
112+
cursor: 'pointer',
113+
padding: '0.25rem',
114+
lineHeight: 1,
115+
fontSize: '1.5rem',
116+
color: '#000',
117+
}}
118+
>
119+
120+
</button>
121+
122+
<h2
123+
style={{
124+
fontFamily: 'Montserrat, sans-serif',
125+
fontSize: '2rem',
126+
fontWeight: 700,
127+
lineHeight: 1.2,
128+
marginBottom: '1.25rem',
129+
color: '#000',
130+
}}
131+
>
132+
Bright Inventions is now Framna
133+
</h2>
134+
135+
<p
136+
style={{
137+
fontFamily: 'Lato, sans-serif',
138+
fontSize: '1.125rem',
139+
lineHeight: 1.6,
140+
color: '#333',
141+
marginBottom: '2rem',
142+
}}
143+
>
144+
We partner with industry leaders (and those about to be) to create digital products that
145+
define markets, reshape industries, and drive meaningful growth.
146+
</p>
147+
148+
<div>
149+
<a
150+
href='https://framna.com/'
151+
target='_blank'
152+
rel='noopener noreferrer'
153+
style={{
154+
display: 'inline-block',
155+
backgroundColor: '#000',
156+
color: '#fff',
157+
fontFamily: 'Montserrat, sans-serif',
158+
fontWeight: 600,
159+
fontSize: '1rem',
160+
padding: '0.875rem 2rem',
161+
borderRadius: '2rem',
162+
textDecoration: 'none',
163+
}}
164+
>
165+
Visit Framna
166+
</a>
167+
</div>
168+
</div>
169+
</div>
170+
</div>
171+
)
172+
}
173+
174+
export default FramnaAnnouncementPopup

src/layout/Page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { useLocation } from '@reach/router'
1111
import { MDXComponentsWrapper } from '../mdx'
1212
import CookiesNotice from '../analytics/cookies-notice'
1313
import { useTranslation } from 'react-i18next'
14+
import FramnaAnnouncementPopup from '../components/shared/FramnaAnnouncementPopup'
1415

1516
export const Page: React.FC<PropsWithChildren<{ className?: string }>> = ({ children, className }) => {
1617
const [mobileMenuOpened, setMobileMenuOpened] = useState(false)
@@ -34,6 +35,7 @@ export const Page: React.FC<PropsWithChildren<{ className?: string }>> = ({ chil
3435
<TopNavigation path={pathname} toggled={setMobileMenuOpened} />
3536
<MDXComponentsWrapper>{children}</MDXComponentsWrapper>
3637
<CookiesNotice />
38+
<FramnaAnnouncementPopup />
3739
<Footer />
3840
</div>
3941
)

0 commit comments

Comments
 (0)