Skip to content

Commit c34b4cf

Browse files
Add Framna announcement popup (#5425)
Shows a modal popup announcing that Bright Inventions joined Framna. - Appears after page fully loads (500ms delay post-load event) - Shows only once per session (sessionStorage) - On production: only shows from 18.03.2026 - On staging (GATSBY_ACTIVE_ENV=staging): shows immediately - "Visit Framna" button links to https://framna.com/ - Dismissible via X button Closes #5423 Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Piotr Mionskowski <miensol@users.noreply.github.com>
1 parent a740a66 commit c34b4cf

File tree

2 files changed

+230
-0
lines changed

2 files changed

+230
-0
lines changed
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
import React, { useEffect, useState } from 'react'
2+
import Modal from 'react-modal'
3+
import styled from 'styled-components'
4+
import variables, { roundedCorners } from '../../styles/variables'
5+
6+
if (typeof window !== 'undefined') {
7+
Modal.setAppElement('#___gatsby')
8+
}
9+
10+
const SESSION_KEY = 'framna_announcement_shown'
11+
12+
// Production: only show from 18.03.2026
13+
// Staging (GATSBY_ACTIVE_ENV=staging): show from today
14+
const SHOW_FROM_DATE = process.env.GATSBY_ACTIVE_ENV === 'staging'
15+
? new Date(0) // always show on staging
16+
: new Date('2026-03-18T00:00:00')
17+
18+
const overlayStyles: React.CSSProperties = {
19+
zIndex: 1002,
20+
background: 'rgba(10, 10, 10, 0.65)',
21+
display: 'flex',
22+
alignItems: 'center',
23+
justifyContent: 'center',
24+
}
25+
26+
const PopupContainer = styled.div`
27+
display: flex;
28+
border-radius: 16px;
29+
overflow: hidden;
30+
max-width: 700px;
31+
width: 100%;
32+
min-height: 320px;
33+
position: relative;
34+
background: #fff;
35+
36+
@media ${variables.device.mobile} {
37+
flex-direction: column;
38+
max-width: 90vw;
39+
}
40+
`
41+
42+
const LeftPanel = styled.div`
43+
background: #5bce4a;
44+
flex: 0 0 45%;
45+
display: flex;
46+
align-items: center;
47+
justify-content: center;
48+
padding: ${variables.pxToRem(40)};
49+
50+
@media ${variables.device.mobile} {
51+
padding: ${variables.pxToRem(32)} ${variables.pxToRem(24)};
52+
flex: 0 0 auto;
53+
}
54+
`
55+
56+
const RightPanel = styled.div`
57+
flex: 1;
58+
padding: ${variables.pxToRem(48)} ${variables.pxToRem(40)};
59+
display: flex;
60+
flex-direction: column;
61+
justify-content: center;
62+
position: relative;
63+
64+
@media ${variables.device.mobile} {
65+
padding: ${variables.pxToRem(32)} ${variables.pxToRem(24)} ${variables.pxToRem(40)};
66+
}
67+
`
68+
69+
const CloseButton = styled.button`
70+
position: absolute;
71+
top: ${variables.pxToRem(16)};
72+
right: ${variables.pxToRem(16)};
73+
background: transparent;
74+
border: none;
75+
cursor: pointer;
76+
padding: ${variables.pxToRem(8)};
77+
line-height: 0;
78+
color: ${variables.color.text};
79+
80+
&:hover {
81+
opacity: 0.6;
82+
}
83+
`
84+
85+
const PopupTitle = styled.h2`
86+
font-family: ${variables.font.montserrat};
87+
font-size: ${variables.pxToRem(28)};
88+
font-weight: 800;
89+
line-height: 1.2;
90+
color: ${variables.color.text};
91+
margin: 0 0 ${variables.pxToRem(16)};
92+
93+
@media ${variables.device.mobile} {
94+
font-size: ${variables.pxToRem(22)};
95+
}
96+
`
97+
98+
const PopupText = styled.p`
99+
font-family: ${variables.font.lato};
100+
font-size: ${variables.pxToRem(16)};
101+
line-height: 1.6;
102+
color: ${variables.color.text};
103+
margin: 0 0 ${variables.pxToRem(28)};
104+
`
105+
106+
const VisitButton = styled.a`
107+
display: inline-block;
108+
background: ${variables.color.text};
109+
color: ${variables.color.white};
110+
font-family: ${variables.font.montserrat};
111+
font-size: ${variables.pxToRem(16)};
112+
font-weight: 600;
113+
padding: ${variables.pxToRem(14)} ${variables.pxToRem(28)};
114+
border-radius: ${roundedCorners};
115+
text-decoration: none;
116+
transition: opacity 0.2s ease;
117+
align-self: flex-start;
118+
119+
&:hover {
120+
opacity: 0.8;
121+
}
122+
`
123+
124+
const FramnaLogoWrapper = styled.div`
125+
display: flex;
126+
align-items: center;
127+
gap: ${variables.pxToRem(10)};
128+
`
129+
130+
const FramnaLogoText = styled.span`
131+
font-family: ${variables.font.montserrat};
132+
font-size: ${variables.pxToRem(32)};
133+
font-weight: 700;
134+
color: ${variables.color.text};
135+
letter-spacing: -0.5px;
136+
137+
@media ${variables.device.mobile} {
138+
font-size: ${variables.pxToRem(24)};
139+
}
140+
`
141+
142+
function FramnaIcon() {
143+
return (
144+
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
145+
<path
146+
d="M18 4C18 4 10 10 10 20C10 25.523 13.477 30 18 30C22.523 30 26 25.523 26 20C26 10 18 4 18 4Z"
147+
fill={variables.color.text}
148+
opacity="0.15"
149+
/>
150+
<path
151+
d="M18 8C18 8 12 13 12 21C12 25.418 14.686 29 18 29"
152+
stroke={variables.color.text}
153+
strokeWidth="2.5"
154+
strokeLinecap="round"
155+
/>
156+
<path
157+
d="M18 14C18 14 22 17 22 22"
158+
stroke={variables.color.text}
159+
strokeWidth="2.5"
160+
strokeLinecap="round"
161+
/>
162+
<circle cx="18" cy="30" r="2" fill={variables.color.text} />
163+
</svg>
164+
)
165+
}
166+
167+
export function FramnaAnnouncementPopup() {
168+
const [isOpen, setIsOpen] = useState(false)
169+
170+
useEffect(() => {
171+
const now = new Date()
172+
if (now < SHOW_FROM_DATE) return
173+
if (typeof window === 'undefined') return
174+
if (sessionStorage.getItem(SESSION_KEY)) return
175+
176+
// Show after page fully loads
177+
const onLoad = () => {
178+
setTimeout(() => {
179+
setIsOpen(true)
180+
}, 500)
181+
}
182+
183+
if (document.readyState === 'complete') {
184+
onLoad()
185+
} else {
186+
window.addEventListener('load', onLoad)
187+
return () => window.removeEventListener('load', onLoad)
188+
}
189+
}, [])
190+
191+
function handleClose() {
192+
sessionStorage.setItem(SESSION_KEY, '1')
193+
setIsOpen(false)
194+
}
195+
196+
return (
197+
<Modal
198+
isOpen={isOpen}
199+
onRequestClose={handleClose}
200+
style={{ overlay: overlayStyles, content: { inset: 'auto', padding: 0, border: 'none', background: 'transparent', borderRadius: 0, maxWidth: '700px', width: '90%', margin: 'auto' } }}
201+
contentLabel="Bright Inventions is now Framna"
202+
>
203+
<PopupContainer>
204+
<LeftPanel>
205+
<FramnaLogoWrapper>
206+
<FramnaIcon />
207+
<FramnaLogoText>framna</FramnaLogoText>
208+
</FramnaLogoWrapper>
209+
</LeftPanel>
210+
<RightPanel>
211+
<CloseButton onClick={handleClose} aria-label="Close">
212+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
213+
<path d="M2 2L18 18M18 2L2 18" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" />
214+
</svg>
215+
</CloseButton>
216+
<PopupTitle>Bright Inventions is now Framna</PopupTitle>
217+
<PopupText>
218+
We partner with industry leaders (and those about to be) to create digital products that define markets,
219+
reshape industries, and drive meaningful growth.
220+
</PopupText>
221+
<VisitButton href="https://framna.com/" target="_blank" rel="noopener noreferrer">
222+
Visit Framna
223+
</VisitButton>
224+
</RightPanel>
225+
</PopupContainer>
226+
</Modal>
227+
)
228+
}

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)