|
33 | 33 | <meta name="twitter:description" content="{{ page.description | default: site.description }}"> |
34 | 34 | <meta name="twitter:image" content="{{ '/assets/images/og-image.png' | absolute_url }}"> |
35 | 35 |
|
36 | | - <!-- Google tag (gtag.js) - cookieless --> |
37 | | - <script async src="https://www.googletagmanager.com/gtag/js?id=G-FMRJ311LEF"></script> |
38 | | - <script> |
39 | | - window.dataLayer = window.dataLayer || []; |
40 | | - function gtag(){dataLayer.push(arguments);} |
41 | | - |
42 | | - gtag('consent', 'default', { |
43 | | - 'analytics_storage': 'denied', |
44 | | - 'ad_storage': 'denied' |
45 | | - }); |
46 | | - |
47 | | - gtag('js', new Date()); |
48 | | - gtag('config', 'G-FMRJ311LEF'); |
49 | | - </script> |
50 | | - |
51 | 36 | <!-- Favicon --> |
52 | 37 | <link rel="icon" type="image/svg+xml" href="{{ '/assets/images/favicon.svg' | relative_url }}"> |
53 | 38 |
|
54 | 39 | <!-- Theme Color --> |
55 | 40 | <meta name="theme-color" content="#785D8F"> |
56 | 41 | <meta name="msapplication-TileColor" content="#785D8F"> |
57 | 42 |
|
58 | | - <!-- Fonts --> |
| 43 | + <!-- Preconnect for performance --> |
59 | 44 | <link rel="preconnect" href="https://fonts.googleapis.com"> |
60 | 45 | <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
61 | | - <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> |
| 46 | + <link rel="dns-prefetch" href="https://www.googletagmanager.com"> |
62 | 47 |
|
63 | | - <!-- Stylesheet --> |
64 | | - <link rel="stylesheet" href="{{ '/assets/css/style.css' | relative_url }}"> |
| 48 | + <!-- Critical CSS inline --> |
| 49 | + <style> |
| 50 | + body{font-family:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;margin:0;background:#fff} |
| 51 | + .nav{display:flex;justify-content:space-between;align-items:center;padding:20px 60px;max-width:1280px;margin:0 auto} |
| 52 | + .main{max-width:860px;margin:0 auto;padding:40px 60px} |
| 53 | + </style> |
| 54 | + |
| 55 | + <!-- Stylesheet - non-blocking --> |
| 56 | + <link rel="preload" href="{{ '/assets/css/style.css' | relative_url }}" as="style" onload="this.onload=null;this.rel='stylesheet'"> |
| 57 | + <noscript><link rel="stylesheet" href="{{ '/assets/css/style.css' | relative_url }}"></noscript> |
| 58 | + |
| 59 | + <!-- Fonts - non-blocking --> |
| 60 | + <link rel="preload" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" as="style" onload="this.onload=null;this.rel='stylesheet'"> |
| 61 | + <noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"></noscript> |
65 | 62 |
|
66 | 63 | <!-- Structured Data --> |
67 | 64 | <script type="application/ld+json"> |
|
116 | 113 | </div> |
117 | 114 | </footer> |
118 | 115 |
|
| 116 | + <!-- Scripts at end of body --> |
119 | 117 | <script> |
120 | | - // TOC navigation |
121 | | - document.querySelectorAll('.toc a').forEach(link => { |
122 | | - link.addEventListener('click', function(e) { |
123 | | - e.preventDefault(); |
124 | | - const text = this.textContent.trim().toLowerCase(); |
125 | | - const headings = document.querySelectorAll('h2'); |
126 | | - for (const h of headings) { |
127 | | - if (h.textContent.toLowerCase().includes(text)) { |
128 | | - h.scrollIntoView({ behavior: 'smooth', block: 'start' }); |
129 | | - break; |
130 | | - } |
131 | | - } |
132 | | - }); |
133 | | - }); |
| 118 | + // Dark mode - run immediately to prevent flash |
| 119 | + (function(){ |
| 120 | + var d=document.body,t=document.getElementById('dark-toggle'), |
| 121 | + s=localStorage.getItem('darkMode'), |
| 122 | + p=window.matchMedia('(prefers-color-scheme:dark)').matches; |
| 123 | + if(s==='true'||(s===null&&p)){d.classList.add('dark');if(t)t.checked=true} |
| 124 | + if(t)t.onchange=function(){d.classList.toggle('dark');localStorage.setItem('darkMode',d.classList.contains('dark'))} |
| 125 | + })(); |
| 126 | + </script> |
134 | 127 |
|
| 128 | + <!-- Deferred scripts --> |
| 129 | + <script defer> |
135 | 130 | // Back to top |
136 | | - const backToTop = document.getElementById('back-to-top'); |
137 | | - window.addEventListener('scroll', () => { |
138 | | - if (window.scrollY > 400) { |
139 | | - backToTop.classList.add('visible'); |
140 | | - } else { |
141 | | - backToTop.classList.remove('visible'); |
| 131 | + var b=document.getElementById('back-to-top'); |
| 132 | + window.onscroll=function(){b.classList.toggle('visible',window.scrollY>400)}; |
| 133 | + b.onclick=function(){window.scrollTo({top:0,behavior:'smooth'})}; |
| 134 | + |
| 135 | + // TOC navigation |
| 136 | + document.querySelectorAll('.toc a').forEach(function(l){ |
| 137 | + l.onclick=function(e){ |
| 138 | + e.preventDefault(); |
| 139 | + var t=this.textContent.trim().toLowerCase(); |
| 140 | + document.querySelectorAll('h2').forEach(function(h){ |
| 141 | + if(h.textContent.toLowerCase().includes(t))h.scrollIntoView({behavior:'smooth',block:'start'}) |
| 142 | + }) |
142 | 143 | } |
143 | 144 | }); |
144 | | - backToTop.addEventListener('click', () => { |
145 | | - window.scrollTo({ top: 0, behavior: 'smooth' }); |
146 | | - }); |
147 | 145 |
|
148 | 146 | // Copy code button |
149 | | - document.querySelectorAll('pre').forEach(pre => { |
150 | | - const btn = document.createElement('button'); |
151 | | - btn.className = 'copy-btn'; |
152 | | - btn.textContent = 'Copy'; |
153 | | - btn.addEventListener('click', () => { |
154 | | - const code = pre.querySelector('code') || pre; |
155 | | - navigator.clipboard.writeText(code.textContent).then(() => { |
156 | | - btn.textContent = 'Copied!'; |
157 | | - setTimeout(() => btn.textContent = 'Copy', 2000); |
158 | | - }); |
159 | | - }); |
160 | | - pre.style.position = 'relative'; |
161 | | - pre.appendChild(btn); |
| 147 | + document.querySelectorAll('pre').forEach(function(p){ |
| 148 | + var b=document.createElement('button'); |
| 149 | + b.className='copy-btn';b.textContent='Copy'; |
| 150 | + b.onclick=function(){ |
| 151 | + navigator.clipboard.writeText((p.querySelector('code')||p).textContent).then(function(){ |
| 152 | + b.textContent='Copied!';setTimeout(function(){b.textContent='Copy'},2000) |
| 153 | + }) |
| 154 | + }; |
| 155 | + p.style.position='relative';p.appendChild(b) |
162 | 156 | }); |
| 157 | + </script> |
163 | 158 |
|
164 | | - // Dark mode |
165 | | - const darkToggle = document.getElementById('dark-toggle'); |
166 | | - const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; |
167 | | - const stored = localStorage.getItem('darkMode'); |
| 159 | + <!-- Google tag (gtag.js) - cookieless --> |
| 160 | + <script async src="https://www.googletagmanager.com/gtag/js?id=G-FMRJ311LEF"></script> |
| 161 | + <script> |
| 162 | + window.dataLayer = window.dataLayer || []; |
| 163 | + function gtag(){dataLayer.push(arguments);} |
168 | 164 |
|
169 | | - if (stored === 'true' || (stored === null && prefersDark)) { |
170 | | - document.body.classList.add('dark'); |
171 | | - if (darkToggle) darkToggle.checked = true; |
172 | | - } |
| 165 | + gtag('consent', 'default', { |
| 166 | + 'analytics_storage': 'denied', |
| 167 | + 'ad_storage': 'denied' |
| 168 | + }); |
173 | 169 |
|
174 | | - if (darkToggle) { |
175 | | - darkToggle.addEventListener('change', () => { |
176 | | - document.body.classList.toggle('dark'); |
177 | | - localStorage.setItem('darkMode', document.body.classList.contains('dark')); |
178 | | - }); |
179 | | - } |
| 170 | + gtag('js', new Date()); |
| 171 | + gtag('config', 'G-FMRJ311LEF'); |
180 | 172 | </script> |
181 | 173 | </body> |
182 | 174 | </html> |
0 commit comments