5757 opacity : 0.85 ;
5858 margin : 0 ;
5959 }
60- # source-link {
60+ # metrics {
6161 position : fixed;
62- top : 20px ;
63- right : 20px ;
62+ bottom : 24px ;
63+ left : 24px ;
64+ display : inline-flex;
65+ align-items : center;
66+ justify-content : center;
67+ gap : 0 ;
68+ padding : 10px ;
69+ border-radius : 999px ;
70+ border : 1px solid rgba (96 , 158 , 255 , 0.35 );
71+ background : linear-gradient (135deg , rgba (18 , 30 , 58 , 0.85 ), rgba (8 , 12 , 28 , 0.85 ));
72+ box-shadow : 0 12px 28px rgba (10 , 22 , 48 , 0.45 ), inset 0 0 12px rgba (64 , 124 , 255 , 0.25 );
73+ font-size : 0.78rem ;
74+ letter-spacing : 0.14em ;
75+ text-transform : uppercase;
76+ backdrop-filter : blur (12px );
77+ z-index : 8 ;
78+ overflow : hidden;
79+ max-width : 56px ;
80+ min-height : 46px ;
81+ box-sizing : border-box;
82+ transition : max-width 0.28s ease, padding 0.28s ease, border-color 0.28s ease;
83+ }
84+ # metrics : hover ,
85+ # metrics : focus-within {
86+ max-width : 320px ;
87+ padding : 8px 14px ;
88+ border-color : rgba (126 , 188 , 255 , 0.6 );
89+ justify-content : flex-start;
90+ }
91+ # source-link {
6492 display : inline-flex;
65- color : inherit;
93+ align-items : center;
94+ justify-content : center;
95+ width : 26px ;
96+ height : 26px ;
97+ border-radius : 50% ;
98+ color : # d7e5ff ;
6699 text-decoration : none;
100+ opacity : 0.8 ;
101+ transition : opacity 0.2s ease, transform 0.2s ease;
67102 }
68103 # source-link svg {
69- width : 24 px ;
70- height : 24 px ;
104+ width : 20 px ;
105+ height : 20 px ;
71106 fill : currentColor;
72- transition : transform 0.2s ease, opacity 0.2s ease;
73107 }
74- # source-link : hover svg ,
75- # source-link : focus svg {
76- transform : scale (1.05 );
108+ # source-link : hover ,
109+ # source-link : focus-visible {
110+ opacity : 1 ;
111+ transform : translateY (-1px );
112+ }
113+ .metrics-details {
114+ display : inline-flex;
115+ align-items : center;
116+ gap : 12px ;
117+ opacity : 0 ;
118+ transform : translateX (-6px );
119+ pointer-events : none;
120+ max-width : 0 ;
121+ flex : 0 1 0% ;
122+ overflow : hidden;
123+ margin-left : 0 ;
124+ transition : opacity 0.18s ease, transform 0.2s ease, max-width 0.28s ease, margin-left 0.28s ease;
125+ }
126+ # metrics : hover .metrics-details ,
127+ # metrics : focus-within .metrics-details {
128+ opacity : 1 ;
129+ transform : translateX (0 );
130+ pointer-events : auto;
131+ max-width : 260px ;
132+ flex-basis : 260px ;
133+ margin-left : 12px ;
134+ }
135+ # metrics label {
136+ position : relative;
137+ display : inline-flex;
138+ align-items : center;
139+ gap : 6px ;
140+ color : # d7e5ff ;
141+ font-weight : 600 ;
142+ cursor : default;
143+ }
144+ # metrics label ::before {
145+ content : '' ;
146+ width : 16px ;
147+ height : 16px ;
148+ background-repeat : no-repeat;
149+ background-size : contain;
77150 opacity : 0.85 ;
78151 }
152+ # metrics label ::after {
153+ position : absolute;
154+ bottom : 120% ;
155+ left : 50% ;
156+ padding : 4px 8px ;
157+ border-radius : 6px ;
158+ background : rgba (12 , 20 , 40 , 0.9 );
159+ box-shadow : 0 6px 14px rgba (6 , 12 , 28 , 0.3 );
160+ color : rgba (215 , 229 , 255 , 0.85 );
161+ font-size : 0.65rem ;
162+ letter-spacing : 0.1em ;
163+ text-transform : uppercase;
164+ white-space : nowrap;
165+ transform : translate (-50% , 4px );
166+ opacity : 0 ;
167+ pointer-events : none;
168+ transition : opacity 0.18s ease, transform 0.18s ease;
169+ content : attr (data-hint);
170+ }
171+ # metrics label : hover ::after ,
172+ # metrics label : focus-visible ::after {
173+ opacity : 1 ;
174+ transform : translate (-50% , 0 );
175+ }
176+ # uv_label ::before {
177+ background-image : url ("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23d7e5ff' d='M8 7a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm0 1.5c-2.9 0-5.5 1.31-5.5 3.25V13c0 .55.45 1 1 1h9c.55 0 1-.45 1-1v-1.25C13.5 9.81 10.9 8.5 8 8.5Z'/%3E%3C/svg%3E" );
178+ }
179+ # pv_label ::before {
180+ background-image : url ("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23d7e5ff' d='M8 3.5c3.04 0 5.64 1.84 6.94 4.5-1.3 2.66-3.9 4.5-6.94 4.5S2.36 10.66 1.06 8C2.36 5.34 4.96 3.5 8 3.5Zm0 2.5a2 2 0 1 0 0 4 2 2 0 0 0 0-4Z'/%3E%3C/svg%3E" );
181+ }
182+ # metrics .separator {
183+ color : rgba (215 , 229 , 255 , 0.45 );
184+ font-size : 0.7rem ;
185+ letter-spacing : normal;
186+ }
79187 </ style >
80188 < script src ="./coi-serviceworker.min.js "> </ script >
189+ < script defer src ="https://stateflare.yuchanns.xyz/track.js "> </ script >
81190</ head >
82191< body >
83192 < div id ="overlay ">
@@ -88,16 +197,25 @@ <h1 id="overlay-title"></h1>
88197 </ div >
89198 </ div >
90199 < canvas id ="canvas " oncontextmenu ="event.preventDefault() "> </ canvas >
91- < a
92- id ="source-link "
93- href ="https://github.com/cloudwu/deepfuture "
94- target ="_blank "
95- rel ="noopener noreferrer "
96- >
97- < svg viewBox ="0 0 16 16 " aria-hidden ="true ">
98- < path d ="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8 " />
99- </ svg >
100- </ a >
200+ < div id ="metrics " aria-live ="polite " aria-expanded ="false ">
201+ < a
202+ id ="source-link "
203+ href ="https://github.com/cloudwu/deepfuture "
204+ target ="_blank "
205+ rel ="noopener noreferrer "
206+ aria-label ="Source code on GitHub "
207+ >
208+ < svg viewBox ="0 0 16 16 " aria-hidden ="true ">
209+ < path d ="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8 " />
210+ </ svg >
211+ </ a >
212+ < div class ="metrics-details ">
213+ < span class ="separator " aria-hidden ="true "> /</ span >
214+ < label id ="uv_label " data-hint ="UV " aria-label ="Unique Visitors " title ="UV "> </ label >
215+ < span class ="separator " aria-hidden ="true "> /</ span >
216+ < label id ="pv_label " data-hint ="PV " aria-label ="Page Views " title ="PV "> </ label >
217+ </ div >
218+ </ div >
101219
102220 < script >
103221 ( function ( ) {
@@ -106,6 +224,45 @@ <h1 id="overlay-title"></h1>
106224 const introEl = document . getElementById ( 'overlay-intro' ) ;
107225 const statusEl = document . getElementById ( 'overlay-status' ) ;
108226 const sourceLinkEl = document . getElementById ( 'source-link' ) ;
227+ const uvLabel = document . getElementById ( 'uv_label' ) ;
228+ const pvLabel = document . getElementById ( 'pv_label' ) ;
229+ const metrics = document . getElementById ( 'metrics' ) ;
230+
231+ function attachLabelSanitizer ( label , prefix ) {
232+ if ( ! label ) return ;
233+ const config = { childList : true , characterData : true , subtree : true } ;
234+ const regex = new RegExp ( '^\\s*' + prefix + '\\s*[::\\-–]?\\s*' , 'i' ) ;
235+
236+ const apply = ( ) => {
237+ const raw = label . textContent || '' ;
238+ if ( ! raw ) return ;
239+ const cleaned = raw . replace ( regex , '' ) . trim ( ) ;
240+ if ( cleaned !== raw ) {
241+ observer . disconnect ( ) ;
242+ label . textContent = cleaned ;
243+ observer . observe ( label , config ) ;
244+ }
245+ } ;
246+
247+ let observer = new MutationObserver ( apply ) ;
248+ observer . observe ( label , config ) ;
249+ apply ( ) ;
250+ }
251+
252+ attachLabelSanitizer ( uvLabel , 'uv' ) ;
253+ attachLabelSanitizer ( pvLabel , 'pv' ) ;
254+
255+ if ( metrics ) {
256+ const setExpanded = ( expanded ) => metrics . setAttribute ( 'aria-expanded' , expanded ? 'true' : 'false' ) ;
257+ metrics . addEventListener ( 'mouseenter' , ( ) => setExpanded ( true ) ) ;
258+ metrics . addEventListener ( 'mouseleave' , ( ) => setExpanded ( false ) ) ;
259+ metrics . addEventListener ( 'focusin' , ( ) => setExpanded ( true ) ) ;
260+ metrics . addEventListener ( 'focusout' , ( ) => {
261+ if ( ! metrics . contains ( document . activeElement ) ) {
262+ setExpanded ( false ) ;
263+ }
264+ } ) ;
265+ }
109266
110267 const locale = ( navigator . language || navigator . userLanguage || 'en' ) . toLowerCase ( ) ;
111268 const isChinese = locale . startsWith ( 'zh' ) ;
0 commit comments