33< head >
44 < meta charset ="UTF-8 ">
55 < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
6+ < meta name ="theme-color " content ="#0f172a " />
67 < title > MiSub - 离线模式</ title >
78 < style >
9+ : root {
10+ color-scheme : light dark;
11+ --bg : # f8fafc ;
12+ --card : rgba (255 , 255 , 255 , 0.85 );
13+ --text : # 0f172a ;
14+ --muted : # 64748b ;
15+ --primary : # 4f46e5 ;
16+ --border : rgba (148 , 163 , 184 , 0.2 );
17+ }
18+ @media (prefers-color-scheme : dark) {
19+ : root {
20+ --bg : # 0b1120 ;
21+ --card : rgba (15 , 23 , 42 , 0.75 );
22+ --text : # f8fafc ;
23+ --muted : # 94a3b8 ;
24+ --primary : # 818cf8 ;
25+ --border : rgba (148 , 163 , 184 , 0.2 );
26+ }
27+ }
828 body {
9- font-family : -apple-system , BlinkMacSystemFont , 'Segoe UI' , Roboto , sans-serif;
29+ font-family : 'Plus Jakarta Sans' , 'Outfit' , 'Segoe UI' , sans-serif;
1030 margin : 0 ;
1131 padding : 0 ;
12- background : linear-gradient (135deg , # 667eea 0% , # 764ba2 100% );
1332 min-height : 100vh ;
1433 display : flex;
1534 align-items : center;
1635 justify-content : center;
17- color : white;
36+ background :
37+ radial-gradient (circle at 0% 0% , rgba (99 , 102 , 241 , 0.12 ), transparent 55% ),
38+ radial-gradient (circle at 100% 100% , rgba (14 , 165 , 233 , 0.12 ), transparent 55% ),
39+ var (--bg );
40+ color : var (--text );
1841 }
1942 .container {
2043 text-align : center;
21- padding : 2rem ;
22- max-width : 400px ;
44+ padding : 2.5rem 2.25rem ;
45+ max-width : 440px ;
46+ border-radius : 28px ;
47+ background : var (--card );
48+ border : 1px solid var (--border );
49+ box-shadow : 0 30px 60px -40px rgba (15 , 23 , 42 , 0.6 );
50+ backdrop-filter : blur (12px );
2351 }
2452 .icon {
25- width : 80px ;
26- height : 80px ;
27- margin : 0 auto 2rem ;
28- background : rgba (255 , 255 , 255 , 0.2 );
29- border-radius : 50% ;
53+ width : 88px ;
54+ height : 88px ;
55+ margin : 0 auto 1.5rem ;
56+ border-radius : 24px ;
3057 display : flex;
3158 align-items : center;
3259 justify-content : center;
60+ background : rgba (99 , 102 , 241 , 0.12 );
61+ color : var (--primary );
3362 }
3463 h1 {
3564 font-size : 1.5rem ;
36- margin-bottom : 1 rem ;
37- font-weight : 600 ;
65+ margin-bottom : 0.75 rem ;
66+ font-weight : 700 ;
3867 }
3968 p {
4069 font-size : 1rem ;
41- opacity : 0.9 ;
70+ color : var ( --muted ) ;
4271 line-height : 1.6 ;
43- margin-bottom : 2rem ;
72+ margin-bottom : 1.5rem ;
73+ }
74+ .actions {
75+ display : flex;
76+ gap : 0.75rem ;
77+ justify-content : center;
78+ flex-wrap : wrap;
79+ margin-bottom : 1.5rem ;
4480 }
4581 .btn {
46- background : rgba ( 255 , 255 , 255 , 0.2 );
47- border : 2 px solid rgba ( 255 , 255 , 255 , 0.3 ) ;
82+ background : var ( --primary );
83+ border : none ;
4884 color : white;
49- padding : 0.75 rem 1.5 rem ;
50- border-radius : 0.5 rem ;
51- font-size : 1 rem ;
85+ padding : 0.7 rem 1.4 rem ;
86+ border-radius : 12 px ;
87+ font-size : 0.95 rem ;
5288 cursor : pointer;
53- transition : all 0.3 s ease;
89+ transition : transform 0.2 s ease , box-shadow 0.2 s ease , opacity 0.2 s ease;
5490 text-decoration : none;
55- display : inline-block;
91+ display : inline-flex;
92+ align-items : center;
93+ justify-content : center;
94+ box-shadow : 0 12px 30px -16px rgba (79 , 70 , 229 , 0.7 );
95+ }
96+ .btn .secondary {
97+ background : transparent;
98+ border : 1px solid var (--border );
99+ color : var (--text );
100+ box-shadow : none;
56101 }
57102 .btn : hover {
58- background : rgba (255 , 255 , 255 , 0.3 );
59103 transform : translateY (-1px );
104+ opacity : 0.95 ;
60105 }
61106 .features {
62- margin-top : 2rem ;
63107 text-align : left;
108+ border-top : 1px solid var (--border );
109+ padding-top : 1.25rem ;
110+ margin-top : 1.25rem ;
64111 }
65112 .feature {
66113 display : flex;
67114 align-items : center;
68115 margin-bottom : 0.75rem ;
69116 font-size : 0.9rem ;
117+ color : var (--muted );
118+ }
119+ .feature : last-child {
120+ margin-bottom : 0 ;
70121 }
71122 .feature-icon {
72123 width : 16px ;
73124 height : 16px ;
74125 margin-right : 0.5rem ;
75- opacity : 0.8 ;
126+ color : var (--primary );
127+ }
128+ .status {
129+ display : inline-flex;
130+ align-items : center;
131+ gap : 0.5rem ;
132+ font-size : 0.85rem ;
133+ color : var (--muted );
134+ }
135+ .dot {
136+ width : 8px ;
137+ height : 8px ;
138+ border-radius : 999px ;
139+ background : # f97316 ;
140+ }
141+ .dot .online {
142+ background : # 22c55e ;
76143 }
77144 </ style >
78145</ head >
79146< body >
80147 < div class ="container ">
81148 < div class ="icon ">
82- < svg width ="40 " height ="40 " viewBox ="0 0 24 24 " fill ="none " stroke ="currentColor " stroke-width ="2 ">
83- < path d ="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z "> </ path >
149+ < svg width ="42 " height ="42 " viewBox ="0 0 24 24 " fill ="none " stroke ="currentColor " stroke-width ="2 ">
150+ < path d ="M2 12s3.5-6.5 10-6.5 10 6.5 10 6.5-3.5 6.5-10 6.5-10-6.5-10-6.5z "> </ path >
84151 < circle cx ="12 " cy ="12 " r ="3 "> </ circle >
85152 </ svg >
86153 </ div >
87-
88- < h1 > 您当前处于离线状态</ h1 >
89- < p > 网络连接似乎出现了问题,但您仍然可以查看已缓存的内容。</ p >
90-
91- < button class ="btn " onclick ="window.location.reload() "> 重新连接</ button >
92-
154+
155+ < h1 > 当前离线</ h1 >
156+ < p > 网络暂不可用,但已缓存的页面仍可浏览。恢复连接后将自动同步最新数据。</ p >
157+
158+ < div class ="actions ">
159+ < button class ="btn " onclick ="window.location.reload() "> 重新连接</ button >
160+ < a class ="btn secondary " href ="/ "> 返回主页</ a >
161+ </ div >
162+
163+ < div class ="status ">
164+ < span class ="dot " id ="statusDot "> </ span >
165+ < span id ="statusText "> 离线状态</ span >
166+ </ div >
167+
93168 < div class ="features ">
94169 < div class ="feature ">
95170 < svg class ="feature-icon " viewBox ="0 0 24 24 " fill ="none " stroke ="currentColor " stroke-width ="2 ">
96171 < polyline points ="20,6 9,17 4,12 "> </ polyline >
97172 </ svg >
98- 离线时可查看已缓存的订阅
173+ 已缓存的订阅和配置可继续查看
99174 </ div >
100175 < div class ="feature ">
101176 < svg class ="feature-icon " viewBox ="0 0 24 24 " fill ="none " stroke ="currentColor " stroke-width ="2 ">
102177 < polyline points ="20,6 9,17 4,12 "> </ polyline >
103178 </ svg >
104- 数据会在连接恢复后同步
179+ 恢复网络后自动尝试同步
105180 </ div >
106181 < div class ="feature ">
107182 < svg class ="feature-icon " viewBox ="0 0 24 24 " fill ="none " stroke ="currentColor " stroke-width ="2 ">
108183 < polyline points ="20,6 9,17 4,12 "> </ polyline >
109184 </ svg >
110- PWA应用离线体验优化
185+ 建议保持应用常驻以加速更新
111186 </ div >
112187 </ div >
113188 </ div >
114189
115190 < script >
116- // 定期检查网络连接
117- setInterval ( ( ) => {
118- if ( navigator . onLine ) {
119- window . location . reload ( ) ;
191+ const statusDot = document . getElementById ( 'statusDot' ) ;
192+ const statusText = document . getElementById ( 'statusText' ) ;
193+
194+ const updateStatus = ( ) => {
195+ const online = navigator . onLine ;
196+ statusDot . classList . toggle ( 'online' , online ) ;
197+ statusText . textContent = online ? '已恢复连接' : '离线状态' ;
198+ if ( online ) {
199+ setTimeout ( ( ) => window . location . reload ( ) , 600 ) ;
120200 }
121- } , 5000 ) ;
122-
123- // 监听网络状态变化
124- window . addEventListener ( 'online' , ( ) => {
125- window . location . reload ( ) ;
126- } ) ;
201+ } ;
202+
203+ updateStatus ( ) ;
204+ window . addEventListener ( 'online' , updateStatus ) ;
205+ window . addEventListener ( 'offline' , updateStatus ) ;
206+ setInterval ( updateStatus , 5000 ) ;
127207 </ script >
128208</ body >
129- </ html >
209+ </ html >
0 commit comments