|
1 | 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 | 2 |
|
10 | 3 | const SESSION_KEY = 'framna_announcement_shown' |
11 | 4 |
|
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 | | -} |
| 5 | +// Show from 18.03.2026 in production; on staging show immediately |
| 6 | +const SHOW_FROM = new Date('2026-03-18T00:00:00Z') |
25 | 7 |
|
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 | | -` |
| 8 | +function isStaging(): boolean { |
| 9 | + return process.env.GATSBY_ACTIVE_ENV === 'staging' |
| 10 | +} |
141 | 11 |
|
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 | | - ) |
| 12 | +function shouldShowByDate(): boolean { |
| 13 | + if (isStaging()) return true |
| 14 | + return new Date() >= SHOW_FROM |
165 | 15 | } |
166 | 16 |
|
167 | | -export function FramnaAnnouncementPopup() { |
168 | | - const [isOpen, setIsOpen] = useState(false) |
| 17 | +const FramnaAnnouncementPopup: React.FC = () => { |
| 18 | + const [visible, setVisible] = useState(false) |
169 | 19 |
|
170 | 20 | 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 |
| 21 | + if (!shouldShowByDate()) return |
| 22 | + if (typeof sessionStorage !== 'undefined' && sessionStorage.getItem(SESSION_KEY)) return |
175 | 23 |
|
176 | | - // Show after page fully loads |
177 | | - const onLoad = () => { |
| 24 | + const show = () => { |
178 | 25 | setTimeout(() => { |
179 | | - setIsOpen(true) |
| 26 | + setVisible(true) |
180 | 27 | }, 500) |
181 | 28 | } |
182 | 29 |
|
183 | 30 | if (document.readyState === 'complete') { |
184 | | - onLoad() |
| 31 | + show() |
185 | 32 | } else { |
186 | | - window.addEventListener('load', onLoad) |
187 | | - return () => window.removeEventListener('load', onLoad) |
| 33 | + window.addEventListener('load', show, { once: true }) |
| 34 | + return () => window.removeEventListener('load', show) |
188 | 35 | } |
189 | 36 | }, []) |
190 | 37 |
|
191 | | - function handleClose() { |
192 | | - sessionStorage.setItem(SESSION_KEY, '1') |
193 | | - setIsOpen(false) |
| 38 | + const handleClose = () => { |
| 39 | + setVisible(false) |
| 40 | + if (typeof sessionStorage !== 'undefined') { |
| 41 | + sessionStorage.setItem(SESSION_KEY, '1') |
| 42 | + } |
194 | 43 | } |
195 | 44 |
|
| 45 | + if (!visible) return null |
| 46 | + |
196 | 47 | 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" |
| 48 | + <div |
| 49 | + style={{ |
| 50 | + position: 'fixed', |
| 51 | + inset: 0, |
| 52 | + backgroundColor: 'rgba(0,0,0,0.5)', |
| 53 | + display: 'flex', |
| 54 | + alignItems: 'center', |
| 55 | + justifyContent: 'center', |
| 56 | + zIndex: 9999, |
| 57 | + padding: '16px', |
| 58 | + }} |
| 59 | + onClick={handleClose} |
202 | 60 | > |
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"> |
| 61 | + <div |
| 62 | + style={{ |
| 63 | + display: 'flex', |
| 64 | + borderRadius: '16px', |
| 65 | + overflow: 'hidden', |
| 66 | + maxWidth: '640px', |
| 67 | + width: '100%', |
| 68 | + boxShadow: '0 20px 60px rgba(0,0,0,0.3)', |
| 69 | + }} |
| 70 | + onClick={e => e.stopPropagation()} |
| 71 | + > |
| 72 | + {/* Left green panel */} |
| 73 | + <div |
| 74 | + style={{ |
| 75 | + backgroundColor: '#5EE03A', |
| 76 | + flex: '0 0 45%', |
| 77 | + display: 'flex', |
| 78 | + alignItems: 'center', |
| 79 | + justifyContent: 'center', |
| 80 | + padding: '40px 24px', |
| 81 | + minHeight: '280px', |
| 82 | + }} |
| 83 | + > |
| 84 | + <FramnaLogo /> |
| 85 | + </div> |
| 86 | + |
| 87 | + {/* Right white panel */} |
| 88 | + <div |
| 89 | + style={{ |
| 90 | + backgroundColor: '#ffffff', |
| 91 | + flex: '1', |
| 92 | + padding: '40px 32px', |
| 93 | + position: 'relative', |
| 94 | + display: 'flex', |
| 95 | + flexDirection: 'column', |
| 96 | + justifyContent: 'center', |
| 97 | + }} |
| 98 | + > |
| 99 | + {/* Close button */} |
| 100 | + <button |
| 101 | + onClick={handleClose} |
| 102 | + aria-label='Close' |
| 103 | + style={{ |
| 104 | + position: 'absolute', |
| 105 | + top: '16px', |
| 106 | + right: '16px', |
| 107 | + background: 'none', |
| 108 | + border: 'none', |
| 109 | + cursor: 'pointer', |
| 110 | + padding: '4px', |
| 111 | + lineHeight: 1, |
| 112 | + fontSize: '20px', |
| 113 | + color: '#000', |
| 114 | + }} |
| 115 | + > |
| 116 | + ✕ |
| 117 | + </button> |
| 118 | + |
| 119 | + <h2 |
| 120 | + style={{ |
| 121 | + fontSize: '28px', |
| 122 | + fontWeight: 700, |
| 123 | + lineHeight: 1.2, |
| 124 | + margin: '0 0 16px 0', |
| 125 | + color: '#000', |
| 126 | + }} |
| 127 | + > |
| 128 | + Bright Inventions is now Framna |
| 129 | + </h2> |
| 130 | + |
| 131 | + <p |
| 132 | + style={{ |
| 133 | + fontSize: '16px', |
| 134 | + lineHeight: 1.6, |
| 135 | + margin: '0 0 28px 0', |
| 136 | + color: '#333', |
| 137 | + }} |
| 138 | + > |
| 139 | + We partner with industry leaders (and those about to be) to create digital products that |
| 140 | + define markets, reshape industries, and drive meaningful growth. |
| 141 | + </p> |
| 142 | + |
| 143 | + <a |
| 144 | + href='https://framna.com/' |
| 145 | + target='_blank' |
| 146 | + rel='noopener noreferrer' |
| 147 | + style={{ |
| 148 | + display: 'inline-block', |
| 149 | + backgroundColor: '#000', |
| 150 | + color: '#fff', |
| 151 | + padding: '14px 28px', |
| 152 | + borderRadius: '50px', |
| 153 | + fontSize: '16px', |
| 154 | + fontWeight: 600, |
| 155 | + textDecoration: 'none', |
| 156 | + alignSelf: 'flex-start', |
| 157 | + }} |
| 158 | + > |
222 | 159 | Visit Framna |
223 | | - </VisitButton> |
224 | | - </RightPanel> |
225 | | - </PopupContainer> |
226 | | - </Modal> |
| 160 | + </a> |
| 161 | + </div> |
| 162 | + </div> |
| 163 | + </div> |
227 | 164 | ) |
228 | 165 | } |
| 166 | + |
| 167 | +const FramnaLogo: React.FC = () => ( |
| 168 | + <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}> |
| 169 | + {/* Framna sprout icon */} |
| 170 | + <svg width='32' height='32' viewBox='0 0 32 32' fill='none' xmlns='http://www.w3.org/2000/svg'> |
| 171 | + <path |
| 172 | + d='M16 28V16M16 16C16 10 10 6 4 8C8 8 12 12 16 16ZM16 16C16 10 22 6 28 8C24 8 20 12 16 16Z' |
| 173 | + stroke='#000' |
| 174 | + strokeWidth='2' |
| 175 | + strokeLinecap='round' |
| 176 | + strokeLinejoin='round' |
| 177 | + /> |
| 178 | + </svg> |
| 179 | + <span |
| 180 | + style={{ |
| 181 | + fontSize: '28px', |
| 182 | + fontWeight: 700, |
| 183 | + color: '#000', |
| 184 | + letterSpacing: '-0.5px', |
| 185 | + }} |
| 186 | + > |
| 187 | + framna |
| 188 | + </span> |
| 189 | + </div> |
| 190 | +) |
| 191 | + |
| 192 | +export default FramnaAnnouncementPopup |
0 commit comments