11<!DOCTYPE html>
2- < html >
2+ < html lang =" en " >
33
44< head >
55 <!--
3737
3838 < title > PictoTap</ title >
3939 < link rel ="manifest " href ="manifest.json ">
40+
41+ < style >
42+ body {
43+ margin : 0 ;
44+ padding : 0 ;
45+ background-color : # 673AB7 ;
46+ overflow : hidden;
47+ }
48+
49+ # loading {
50+ display : flex;
51+ flex-direction : column;
52+ align-items : center;
53+ justify-content : center;
54+ height : 100vh ;
55+ font-family : -apple-system, BlinkMacSystemFont, 'Segoe UI' , Roboto, sans-serif;
56+ color : # FFFFFF ;
57+ text-align : center;
58+ padding : 0 24px ;
59+ box-sizing : border-box;
60+ }
61+
62+ # loading h1 {
63+ font-size : 28px ;
64+ font-weight : 700 ;
65+ margin : 16px 0 8px ;
66+ letter-spacing : 0.5px ;
67+ }
68+
69+ # loading .spinner {
70+ width : 40px ;
71+ height : 40px ;
72+ border : 4px solid rgba (255 , 255 , 255 , 0.3 );
73+ border-top-color : # FFFFFF ;
74+ border-radius : 50% ;
75+ animation : spin 0.8s linear infinite;
76+ margin-top : 24px ;
77+ }
78+
79+ @keyframes spin {
80+ to { transform : rotate (360deg ); }
81+ }
82+
83+ # offline-banner {
84+ display : none;
85+ background-color : rgba (0 , 0 , 0 , 0.2 );
86+ color : # FFFFFF ;
87+ padding : 8px 16px ;
88+ border-radius : 8px ;
89+ margin-top : 16px ;
90+ font-size : 14px ;
91+ }
92+ </ style >
4093</ head >
4194
4295< body >
96+ < div id ="loading " aria-label ="Loading PictoTap ">
97+ < h1 > PictoTap</ h1 >
98+ < div class ="spinner " aria-hidden ="true "> </ div >
99+ < div id ="offline-banner " role ="status " aria-live ="polite "> </ div >
100+ </ div >
101+
102+ < script >
103+ const offlineBanner = document . getElementById ( 'offline-banner' ) ;
104+
105+ const offlineMessages = {
106+ en : { cached : 'Offline — loading from cache' , noCached : 'Offline — a first load with internet is required' } ,
107+ es : { cached : 'Sin conexión — cargando desde caché' , noCached : 'Sin conexión — se necesita una primera carga con internet' } ,
108+ ca : { cached : 'Sense connexió — carregant des de la memòria cau' , noCached : 'Sense connexió — cal una primera càrrega amb internet' } ,
109+ eu : { cached : 'Konexiorik gabe — cachetik kargatzen' , noCached : 'Konexiorik gabe — lehen aldiz internetarekin kargatu behar da' } ,
110+ fr : { cached : 'Hors ligne — chargement depuis le cache' , noCached : 'Hors ligne — un premier chargement avec internet est nécessaire' } ,
111+ gl : { cached : 'Sen conexión — cargando desde a caché' , noCached : 'Sen conexión — precísase unha primeira carga con internet' } ,
112+ pt : { cached : 'Sem conexão — carregando do cache' , noCached : 'Sem conexão — é necessário um primeiro carregamento com internet' } ,
113+ } ;
114+
115+ function getMessages ( ) {
116+ const lang = ( navigator . language || 'en' ) . split ( '-' ) [ 0 ] ;
117+ return offlineMessages [ lang ] || offlineMessages [ 'en' ] ;
118+ }
119+
120+ function updateOfflineStatus ( ) {
121+ if ( ! navigator . onLine ) {
122+ const msg = getMessages ( ) ;
123+ if ( 'serviceWorker' in navigator && navigator . serviceWorker . controller ) {
124+ offlineBanner . textContent = msg . cached ;
125+ } else {
126+ offlineBanner . textContent = msg . noCached ;
127+ }
128+ offlineBanner . style . display = 'block' ;
129+ } else {
130+ offlineBanner . style . display = 'none' ;
131+ }
132+ }
133+
134+ window . addEventListener ( 'online' , updateOfflineStatus ) ;
135+ window . addEventListener ( 'offline' , updateOfflineStatus ) ;
136+ updateOfflineStatus ( ) ;
137+ </ script >
138+
43139 < script src ="flutter_bootstrap.js " async > </ script >
44140</ body >
45141
46- </ html >
142+ </ html >
0 commit comments