1+ <!DOCTYPE html>
2+ <!-- saved from url=(0046)https://qjmnz4vd2y07.statuspage.io/embed/frame -->
3+ < html > < head > < meta http-equiv ="Content-Type " content ="text/html; charset=UTF-8 ">
4+
5+ < meta name ="viewport " content ="width=device-width, initial-scale=1 ">
6+ < title > Frame</ title >
7+ < style type ="text/css ">
8+ body {
9+ margin : 0 ;
10+ padding : 0 ;
11+ font-family : -apple-system, BlinkMacSystemFont, sans-serif;
12+ font-size : 12vh ;
13+ letter-spacing : .5vh ;
14+ }
15+ * { box-sizing : border-box; }
16+ a { color : inherit; }
17+
18+ .frame-wrapper {
19+ display : flex;
20+ background-color : # e67e22 ;
21+ color : # FFFFFF ;
22+ margin : 0 ;
23+ padding : 0 ;
24+ width : 100% ;
25+ height : 100vh ;
26+ border-radius : 3px ;
27+ }
28+
29+ .frame-icon {
30+ flex : 1 ;
31+ padding-top : 14vh ;
32+ font-size : 15vh ;
33+ text-align : center;
34+
35+ -moz-transform : scale (0.5 , 0.5 ) translateY (-35vh );
36+ }
37+
38+ .frame-close {
39+ text-align : right;
40+ min-width : 11vh ;
41+ font-size : 11vh ;
42+ flex : .7 ;
43+ padding : 14vh 14vh 0 0 ;
44+
45+ -moz-transform : scale (0.5 , 0.5 ) translateY (-35vh );
46+ }
47+
48+ .frame-content {
49+ flex : 6 ;
50+ padding : 14vh 0 18vh 2vw ;
51+ display : flex;
52+ flex-direction : column;
53+ }
54+
55+ .incident-title {
56+ word-wrap : break-word;
57+ margin : 0 ;
58+ width : 72vw ;
59+ max-height : 30vh ;
60+ min-height : 16vh ;
61+ overflow : hidden;
62+ }
63+
64+ .incident-title p {
65+ font-size : 12vh ;
66+ letter-spacing : .5vh ;
67+ font-weight : 500 ;
68+ margin : 0 ;
69+ }
70+
71+ .incident-context {
72+ margin-top : 5vh ;
73+ margin-bottom : 5vh ;
74+ font-size : 10vh ;
75+ letter-spacing : .5vh ;
76+ flex : 1 ;
77+ }
78+
79+ .svg-button {
80+ border : none;
81+ background : none;
82+ cursor : pointer;
83+ padding : 1vh 0 2vh 0 ;
84+ }
85+
86+ .frame-wrapper .mobile {
87+ border-radius : 0 ;
88+ }
89+
90+ </ style >
91+ </ head >
92+ < body data-new-gr-c-s-check-loaded ="14.1268.0 " data-gr-ext-installed ="">
93+ < div class ="frame-wrapper " id ="frame-div " style ="background-color: rgb(230, 126, 34); color: rgb(255, 255, 255); "> < div class ="frame-icon ">
94+ < svg width ="1em " height ="1em " viewBox ="0 0 17 17 " version ="1.1 " xmlns ="http://www.w3.org/2000/svg " xmlns:xlink ="http://www.w3.org/1999/xlink " id ="status-embed-svg-exclamation-icon ">
95+ < defs >
96+ < path d ="M13.4161506,4.41651608 L19.5838494,10.5844619 C20.3671375,11.3677813 20.3659678,12.6346542 19.5838494,13.4167144 L13.4161506,19.5839547 C12.6328625,20.3671845 11.3659678,20.3660149 10.5838494,19.5839547 L4.41615055,13.4167144 C3.63286252,12.6334846 3.6340322,11.3666116 4.41615055,10.5844619 L10.5838494,4.41651608 C11.3671375,3.63319669 12.6340322,3.63436641 13.4161506,4.41651608 Z M12,14 C12.552,14 13,13.552 13,13 L13,8 C13,7.448 12.552,7 12,7 C11.448,7 11,7.448 11,8 L11,13 C11,13.552 11.448,14 12,14 Z M12,17 C12.552,17 13,16.552 13,16 C13,15.448 12.552,15 12,15 C11.448,15 11,15.448 11,16 C11,16.552 11.448,17 12,17 Z " id ="path-error "> </ path >
97+ </ defs >
98+ < g stroke ="none " stroke-width ="1 " fill ="none " fill-rule ="evenodd ">
99+ < g transform ="translate(-706.000000, -763.000000) ">
100+ < g id ="global/error " transform ="translate(702.500000, 759.500000) ">
101+ < mask id ="mask-error " fill ="white ">
102+ < use xlink:href ="#path-error "> </ use >
103+ </ mask >
104+ < use id ="Combined-Shape " fill ="#42526E " fill-rule ="evenodd " xlink:href ="#path-error "> </ use >
105+ < g id ="Neutral-/-N000 " mask ="url(#mask-error) " fill ="#FFFFFF " fill-rule ="evenodd ">
106+ < polygon points ="0 24 24 24 24 0 0 0 "> </ polygon >
107+ </ g >
108+ </ g >
109+ </ g >
110+ </ g >
111+ </ svg >
112+
113+ </ div >
114+
115+ < div class ="frame-content ">
116+ < h1 class ="incident-title ">
117+ < p > Status embed installed correctly</ p >
118+ </ h1 >
119+
120+ < div class ="incident-item incident-context " id ="incident-text-div ">
121+ This will be shown if an incident or maintenance is posted on your status page.
122+ </ div >
123+
124+ < div class ="incident-item view-link ">
125+ < a class ="page-link " href ="https://www.streamlitstatus.com/?utm_source=embed " target ="_blank "> View latest updates</ a >
126+ </ div >
127+ </ div >
128+
129+ < div class ="frame-close ">
130+ < button class ="svg-button " onclick ="dismissFrame() ">
131+ < svg width ="1em " height ="1em " viewBox ="0 0 13 13 " version ="1.1 " xmlns ="http://www.w3.org/2000/svg " xmlns:xlink ="http://www.w3.org/1999/xlink " id ="status-embed-svg-close-icon ">
132+ < defs >
133+ < path d ="M10,8.8214887 L14.4107443,4.41074435 C14.7361813,4.08530744 15.2638187,4.08530744 15.5892557,4.41074435 C15.9146926,4.73618126 15.9146926,5.26381874 15.5892557,5.58925565 L11.1785113,10 L15.5892557,14.4107443 C15.9146926,14.7361813 15.9146926,15.2638187 15.5892557,15.5892557 C15.2638187,15.9146926 14.7361813,15.9146926 14.4107443,15.5892557 L10,11.1785113 L5.58925565,15.5892557 C5.26381874,15.9146926 4.73618126,15.9146926 4.41074435,15.5892557 C4.08530744,15.2638187 4.08530744,14.7361813 4.41074435,14.4107443 L8.8214887,10 L4.41074435,5.58925565 C4.08530744,5.26381874 4.08530744,4.73618126 4.41074435,4.41074435 C4.73618126,4.08530744 5.26381874,4.08530744 5.58925565,4.41074435 L10,8.8214887 Z " id ="path-x "> </ path >
134+ </ defs >
135+ < g stroke ="none " stroke-width ="1 " fill ="none " fill-rule ="evenodd ">
136+ < g transform ="translate(-1027.000000, -941.000000) ">
137+ < g id ="global/cross " transform ="translate(1023.500000, 937.500000) ">
138+ < mask id ="mask-x " fill ="white ">
139+ < use xlink:href ="#path-x "> </ use >
140+ </ mask >
141+ < use id ="Combined-Shape " fill ="#42526E " fill-rule ="nonzero " xlink:href ="#path-x "> </ use >
142+ < g id ="Dark-neutral-/-DN070 " mask ="url(#mask-x) " fill ="#FFFFFF " fill-rule ="evenodd ">
143+ < polygon id ="DN70 " points ="0 20 20 20 20 0 0 0 "> </ polygon >
144+ </ g >
145+ </ g >
146+ </ g >
147+ </ g >
148+ </ svg >
149+
150+ </ button >
151+ </ div >
152+ </ div >
153+ < script type ="text/javascript ">
154+ var displayItemCode = '' ;
155+ var lsKeyDismissed = location . hostname + '_dismissed' ;
156+ var unresolvedItems = [ ] ;
157+
158+ // check if we can use localStorage (some users may disable 3rd party cookies)
159+ var localStorageAvailable = true
160+ try {
161+ localStorage . setItem ( 'test' , 'test' ) ;
162+ localStorage . removeItem ( 'test' ) ;
163+ } catch ( e ) {
164+ localStorageAvailable = false ;
165+ }
166+
167+ init = function ( ) {
168+ if ( localStorageAvailable && localStorage . getItem ( lsKeyDismissed ) == null ) {
169+ localStorage . setItem ( lsKeyDismissed , '[]' )
170+ }
171+ clampTitle ( ) ;
172+ showNewItems ( unresolvedItems )
173+ var xhr = new XMLHttpRequest ( ) ;
174+ setInterval ( pollForChanges , 60 * 1000 , '/api/v2/status.json' , xhr ) ;
175+ }
176+
177+ showNewItems = function ( unresolvedItems ) {
178+ var dismissed = [ ] ;
179+
180+ if ( localStorageAvailable ) {
181+ var lsDismissedItem = localStorage . getItem ( lsKeyDismissed ) ;
182+ if ( lsDismissedItem ) {
183+ dismissed = JSON . parse ( lsDismissedItem ) ;
184+ }
185+ }
186+
187+ var dismissedSet = new Set ( ) ;
188+ var nothingToShow = true ;
189+ dismissed . forEach ( function ( d ) {
190+ dismissedSet . add ( d ) ;
191+ } ) ;
192+ unresolvedItems . forEach ( function ( ui ) {
193+ if ( ! dismissedSet . has ( ui ) ) {
194+ showFrame ( ) ;
195+ nothingToShow = false ;
196+ return ;
197+ }
198+ } )
199+ if ( nothingToShow ) {
200+ dismissFrame ( ) ;
201+ }
202+ }
203+
204+ updateIncidentTime = function ( incident_updated_at ) {
205+ var incidentTextDiv = document . getElementById ( 'incident-text-div' )
206+ incidentTextDiv . textContent = 'Last updated ' + timeDifference ( new Date ( incident_updated_at ) )
207+ }
208+
209+ showFrame = function ( ) {
210+ parent . postMessage ( { action : 'showFrame' } , '*' ) ;
211+ }
212+
213+ operateOnFrameJson = function ( callback ) {
214+ var xhr = new XMLHttpRequest ( ) ;
215+ xhr . open ( 'GET' , '/embed/frame.json' ) ;
216+ xhr . setRequestHeader ( "Content-Type" , "application/json;charset=UTF-8" ) ;
217+ xhr . send ( ) ;
218+ xhr . onreadystatechange = function ( ) {
219+ if ( xhr . readyState === 4 && xhr . status === 200 ) {
220+ data = JSON . parse ( xhr . response ) ;
221+ callback ( data ) ;
222+ }
223+ }
224+ }
225+
226+ pollForChanges = function ( url , xhr ) {
227+ xhr . open ( 'GET' , url ) ;
228+ xhr . send ( ) ;
229+ xhr . onreadystatechange = function ( ) {
230+ if ( xhr . readyState === 4 ) {
231+ if ( xhr . status != 304 ) {
232+ operateOnFrameJson ( function ( data ) {
233+ var frameDiv = document . getElementById ( 'frame-div' )
234+
235+ // update frame styles in case we switched mode or the settings were updated
236+ frameDiv . style . backgroundColor = data . background_color
237+ frameDiv . style . color = data . text_color
238+
239+ // update frame content
240+ frameDiv . innerHTML = data . frame_html
241+ if ( "incident_last_updated_at" in data ) {
242+ updateIncidentTime ( data . incident_last_updated_at )
243+ }
244+ unresolvedItems = data . unresolved_items
245+ clampTitle ( )
246+ showNewItems ( unresolvedItems )
247+ } )
248+ }
249+ }
250+ }
251+ }
252+
253+ dismissFrame = function ( ) {
254+ if ( localStorageAvailable ) {
255+ localStorage . setItem ( lsKeyDismissed , JSON . stringify ( unresolvedItems ) ) ;
256+ } else {
257+ console . log ( "You dismissed the flag, but third party cookies are disabled on your browser so the flag will come back the next time you visit the page." )
258+ }
259+
260+ parent . postMessage ( { action : 'dismissFrame' } , '*' ) ;
261+ }
262+
263+ clampTitle = function ( ) {
264+ var div = document . querySelector ( '.incident-title' )
265+ var p = document . querySelector ( '.incident-title p' ) ;
266+ var divHeight = div . clientHeight ;
267+
268+ while ( p . clientHeight > divHeight ) {
269+ var text = p . innerHTML ;
270+
271+ if ( ! / \s / . test ( text ) ) {
272+ // this case handles an infinite loop that occurred when the first word was too long to display in the banner
273+ // this also occurred when the first word was the only word and was too long to display, now we simply
274+ // truncate characters within the word itself.
275+
276+ if ( text . length <= 10 ) {
277+ // There's a certain point at which the zoom can make it so the text's height will never be within the div's height.
278+ // This at least happens on Safari becasue the formatting is weird.
279+ // This makes sure we don't get stuck in an infinite loop in this case.
280+ return ;
281+ }
282+
283+ // replace the last character with ...
284+ p . innerHTML = text . replace ( / \w ( \W * ) $ / , '...' ) ;
285+ } else {
286+ p . innerHTML = text . replace ( / \W * \s ( \S ) * $ / , '...' ) ; // replace last word with ...
287+ }
288+ }
289+ }
290+
291+ timeDifference = function ( previous ) {
292+ var msPerMinute = 60 * 1000 ;
293+ var msPerHour = msPerMinute * 60 ;
294+ var msPerDay = msPerHour * 24 ;
295+ var msPerMonth = msPerDay * 30 ;
296+ var msPerYear = msPerDay * 365 ;
297+ var now = new Date ( ) ;
298+ var elapsedMs = now - previous ;
299+
300+ var elapsed = Math . round ( elapsedMs / msPerMinute ) ;
301+ if ( elapsed == 0 ) {
302+ return '1 minute ago' ;
303+ }
304+ else if ( elapsed < 60 ) {
305+ return elapsed + ' minute' + plural ( elapsed ) + ' ago' ;
306+ }
307+
308+ elapsed = Math . round ( elapsedMs / msPerHour ) ;
309+ if ( elapsed < 24 ) {
310+ return elapsed + ' hour' + plural ( elapsed ) + ' ago' ;
311+ }
312+
313+ elapsed = Math . round ( elapsedMs / msPerDay ) ;
314+ if ( elapsed < 31 ) {
315+ return elapsed + ' day' + plural ( elapsed ) + ' ago' ;
316+ }
317+
318+ elapsed = Math . round ( elapsedMs / msPerMonth ) ;
319+ if ( elapsed < 12 ) {
320+ return elapsed + ' month' + plural ( elapsed ) + ' ago' ;
321+ }
322+
323+ elapsed = Math . round ( elapsedMs / msPerYear ) ;
324+ return elapsed + ' year' + plural ( elapsed ) + ' ago' ;
325+ }
326+
327+ plural = function ( x ) {
328+ return ( x <= 1 ) ? '' : 's' ;
329+ }
330+
331+ init ( ) ;
332+ </ script >
333+
334+
335+ </ body > < grammarly-desktop-integration data-grammarly-shadow-root ="true "> < template shadowrootmode ="open "> < style >
336+ div .grammarly-desktop-integration {
337+ position : absolute;
338+ width : 1px ;
339+ height : 1px ;
340+ padding : 0 ;
341+ margin : -1px ;
342+ overflow : hidden;
343+ clip : rect (0 , 0 , 0 , 0 );
344+ white-space : nowrap;
345+ border : 0 ;
346+ -moz-user-select : none;
347+ -webkit-user-select : none;
348+ -ms-user-select : none;
349+ user-select : none;
350+ }
351+
352+ div .grammarly-desktop-integration : before {
353+ content : attr (data-content);
354+ }
355+ </ style > < div aria-label ="grammarly-integration " role ="group " tabindex ="-1 " class ="grammarly-desktop-integration " data-content ="{"mode":"full","isActive":true,"isUserDisabled":false} "> </ div > </ template > </ grammarly-desktop-integration > </ html >
0 commit comments