| ... | @@ -39,12 +39,14 @@ | ... | @@ -39,12 +39,14 @@ |
| 39 | <h1 class="tagline">T3 Code is the best way to code with AI.</h1> | 39 | <h1 class="tagline">T3 Code is the best way to code with AI.</h1> |
| 40 | | 40 | |
| 41 | <a | 41 | <a |
| | 42 | id="download-btn" |
| 42 | href="https://github.com/pingdotgg/t3code/releases" | 43 | href="https://github.com/pingdotgg/t3code/releases" |
| 43 | target="_blank" | | |
| 44 | rel="noopener noreferrer" | | |
| 45 | class="hero-button" | 44 | class="hero-button" |
| 46 | > | 45 | > |
| 47 | Download now | 46 | <svg class="hero-button-icon hero-button-icon--apple" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 814 1000" aria-hidden="true"><path fill="currentColor" d="M788.1 340.9c-5.8 4.5-108.2 62.2-108.2 190.5 0 148.4 130.3 200.9 134.2 202.2-.6 3.2-20.7 71.9-68.7 141.9-42.8 61.6-87.5 123.1-155.5 123.1s-85.5-39.5-164-39.5c-76.5 0-103.7 40.8-165.9 40.8s-105.6-57-155.5-127C46.7 790.7 0 663 0 541.8c0-194.4 126.4-297.5 250.8-297.5 66.1 0 121.2 43.4 162.7 43.4 39.5 0 101.1-46 176.3-46 28.5 0 130.9 2.6 198.3 99.2zm-234-181.5c31.1-36.9 53.1-88.1 53.1-139.3 0-7.1-.6-14.3-1.9-20.1-50.6 1.9-110.8 33.7-147.1 75.8-28.5 32.4-55.1 83.6-55.1 135.5 0 7.8 1.3 15.6 1.9 18.1 3.2.6 8.4 1.3 13.6 1.3 45.4 0 102.5-30.4 135.5-71.3z"/></svg> |
| | 47 | <svg class="hero-button-icon hero-button-icon--windows" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 88 88" aria-hidden="true"><path fill="currentColor" d="m0 12.402 35.687-4.86.016 34.423-35.67.203zm35.67 33.529.028 34.453L.028 75.48.026 45.7zm4.326-39.025L87.314 0v41.527l-47.318.376zm47.329 39.349-.011 41.34-47.318-6.678-.066-34.739z"/></svg> |
| | 48 | <svg class="hero-button-icon hero-button-icon--linux" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 295" aria-hidden="true"><defs><linearGradient id="lt0" x1="48.548%" x2="51.047%" y1="115.276%" y2="41.364%"><stop offset="0%" stop-color="#FFEED7"/><stop offset="100%" stop-color="#BDBFC2"/></linearGradient><linearGradient id="lt6" x1="49.984%" x2="49.984%" y1="89.845%" y2="40.632%"><stop offset="0%" stop-color="#FFEED7"/><stop offset="100%" stop-color="#BDBFC2"/></linearGradient><linearGradient id="lt8" x1="49.841%" x2="50.241%" y1="13.229%" y2="94.673%"><stop offset="0%" stop-color="#FFF" stop-opacity=".8"/><stop offset="100%" stop-color="#FFF" stop-opacity="0"/></linearGradient><linearGradient id="ltc" x1="53.467%" x2="38.949%" y1="48.921%" y2="98.1%"><stop offset="0%" stop-color="#FFA63F"/><stop offset="100%" stop-color="#FF0"/></linearGradient><linearGradient id="lte" x1="30.581%" x2="65.887%" y1="34.024%" y2="89.175%"><stop offset="0%" stop-color="#FFA63F"/><stop offset="100%" stop-color="#FF0"/></linearGradient><linearGradient id="lti" x1="49.733%" x2="50.558%" y1="17.609%" y2="99.385%"><stop offset="0%" stop-color="#FFA63F"/><stop offset="100%" stop-color="#FF0"/></linearGradient></defs><g fill="none"><path fill="#000" d="M63.213 215.474c-11.387-16.346-13.591-69.606 12.947-102.39C89.292 97.383 92.69 86.455 93.7 71.67c.734-16.805-11.846-66.851 35.537-70.616 48.027-3.857 45.364 43.526 45.088 68.596-.183 21.12 15.52 33.15 26.355 49.68 19.927 30.303 18.274 82.461-3.765 110.745-27.916 35.354-51.791 20.018-67.678 21.304-29.752 1.745-30.762 17.54-66.024-35.905"/><path fill="url(#lt6)" d="M81.027 145.684c6.52-14.785 20.386-40.772 20.662-60.883 0-15.978 47.843-19.835 51.7-3.856 3.856 15.978 13.59 39.853 19.834 51.424 6.245 11.478 24.335 48.118 5.051 80.074-17.356 28.284-69.973 50.69-98.073-3.856-9.55-18.917-7.806-42.333.826-62.903"/><path fill="url(#lt8)" d="M166.428 151.285c0 16.162-15.519 37.1-42.15 36.916-27.456.183-39.118-20.754-39.118-36.916 0-16.161 18.182-29.293 40.588-29.293 22.498.092 40.68 13.132 40.68 29.293"/><path fill="#000" stroke="#000" stroke-width=".977" d="M176.805 117.86c13.59 11.02 38.292 49.587 2.204 74.748-11.846 7.806 10.468 32.508 23.049 19.927 43.618-43.894-1.102-94.308-16.53-111.664-13.774-15.151-25.987 3.49-8.723 16.989z"/><path fill="#000" stroke="#000" stroke-width="1.25" d="M79.925 122.727c-8.907 14.509-30.211 48.669-1.652 66.484 38.384 23.6 27.548 47.108-7.53 25.895-49.404-29.568-5.97-89.257 13.774-112.03 22.59-25.529 4.316 4.683-4.592 19.65z"/><path fill="url(#ltc)" stroke="#E68C3F" stroke-width="6.25" d="M51.835 258.542c-20.57-10.928-50.414 2.112-39.578-27.457 2.204-6.704-3.214-16.805.275-23.325 4.133-7.989 13.04-6.244 18.366-11.57 5.234-5.51 8.54-15.06 18.366-13.59 9.734 1.468 16.254 13.406 23.049 28.099 5.05 10.468 22.865 25.253 21.672 37.007-1.47 17.998-21.948 21.396-42.15 10.836z" transform="translate(10)"/><path fill="url(#lte)" stroke="#E68C3F" stroke-width="6.251" d="M194.445 253.49c15.06-18.273 48.578-14.508 25.988-39.577-4.775-5.418-3.306-16.989-9.183-21.947-6.887-6.061-14.509-1.102-21.488-4.224-6.979-3.398-14.325-9.918-22.865-5.327-8.54 4.684-9.459 16.805-10.285 32.783-.735 11.479-11.203 30.671-5.602 41.231 8.081 16.346 29.11 14.142 43.435-2.938z" transform="translate(10)"/><path fill="url(#lti)" stroke="#E68C3F" stroke-width="3.75" d="M97.107 66.344c3.673-3.398 12.58-13.774 29.477-2.939 3.122 2.02 5.693 2.204 11.662 4.775 12.03 4.96 6.336 16.897-6.52 20.937-5.51 1.745-10.468 8.449-20.386 7.806-8.54-.46-10.744-6.06-15.978-9.091-9.275-5.234-10.652-12.305-5.602-16.07 5.051-3.765 6.98-5.143 7.347-5.418z" transform="translate(10)"/><path fill="#000" d="M133.186 57.712c-.092 5.234 2.48 9.458 5.877 9.458 3.306 0 6.153-4.224 6.245-9.366.091-5.234-2.48-9.459-5.878-9.459-3.397 0-6.152 4.225-6.244 9.367m-21.212.092c.459 4.316-1.194 7.989-3.582 8.356-2.387.276-4.683-2.938-5.142-7.254-.46-4.316 1.194-7.99 3.581-8.357 2.388-.275 4.684 2.939 5.143 7.255"/></g></svg> |
| | 49 | <span id="download-label">Download now</span> |
| 48 | </a> | 50 | </a> |
| 49 | | 51 | |
| 50 | <div class="screenshot-wrap"> | 52 | <div class="screenshot-wrap"> |
| ... | @@ -64,6 +66,90 @@ | ... | @@ -64,6 +66,90 @@ |
| 64 | </body> | 66 | </body> |
| 65 | </html> | 67 | </html> |
| 66 | | 68 | |
| | 69 | <script> |
| | 70 | const REPO = "pingdotgg/t3code"; |
| | 71 | const RELEASES_URL = `https://github.com/${REPO}/releases`; |
| | 72 | const API_URL = `https://api.github.com/repos/${REPO}/releases/latest`; |
| | 73 | |
| | 74 | type Platform = { os: "mac" | "win" | "linux"; label: string; arch?: string }; |
| | 75 | |
| | 76 | function detectPlatform(): Platform | null { |
| | 77 | const ua = navigator.userAgent; |
| | 78 | if (/Win/i.test(ua)) return { os: "win", label: "Download for Windows" }; |
| | 79 | if (/Mac/i.test(ua)) { |
| | 80 | const isArm = |
| | 81 | /arm|aarch/i.test(navigator.platform ?? "") || ua.includes("ARM"); |
| | 82 | return { |
| | 83 | os: "mac", |
| | 84 | label: `Download for macOS`, |
| | 85 | arch: isArm ? "arm64" : "x64", |
| | 86 | }; |
| | 87 | } |
| | 88 | if (/Linux/i.test(ua)) return { os: "linux", label: "Download for Linux" }; |
| | 89 | return null; |
| | 90 | } |
| | 91 | |
| | 92 | function pickAsset( |
| | 93 | assets: Array<{ name: string; browser_download_url: string }>, |
| | 94 | platform: Platform, |
| | 95 | ): string | null { |
| | 96 | if (platform.os === "win") { |
| | 97 | return ( |
| | 98 | assets.find((a) => a.name.endsWith("-x64.exe")) |
| | 99 | ?.browser_download_url ?? null |
| | 100 | ); |
| | 101 | } |
| | 102 | if (platform.os === "mac") { |
| | 103 | const preferred = assets.find((a) => |
| | 104 | a.name.endsWith(`-${platform.arch}.dmg`), |
| | 105 | ); |
| | 106 | const fallback = assets.find((a) => a.name.endsWith(".dmg")); |
| | 107 | return (preferred ?? fallback)?.browser_download_url ?? null; |
| | 108 | } |
| | 109 | if (platform.os === "linux") { |
| | 110 | return ( |
| | 111 | assets.find((a) => a.name.endsWith(".AppImage")) |
| | 112 | ?.browser_download_url ?? null |
| | 113 | ); |
| | 114 | } |
| | 115 | return null; |
| | 116 | } |
| | 117 | |
| | 118 | async function init() { |
| | 119 | const btn = document.getElementById("download-btn") as HTMLAnchorElement | null; |
| | 120 | const label = document.getElementById("download-label"); |
| | 121 | if (!btn || !label) return; |
| | 122 | |
| | 123 | const platform = detectPlatform(); |
| | 124 | if (!platform) return; |
| | 125 | |
| | 126 | document.documentElement.dataset.platform = platform.os; |
| | 127 | label.textContent = platform.label; |
| | 128 | |
| | 129 | try { |
| | 130 | const cached = sessionStorage.getItem("t3code-latest-release"); |
| | 131 | const data = cached |
| | 132 | ? JSON.parse(cached) |
| | 133 | : await fetch(API_URL).then((r) => r.json()); |
| | 134 | |
| | 135 | if (!cached && data?.assets) { |
| | 136 | sessionStorage.setItem("t3code-latest-release", JSON.stringify(data)); |
| | 137 | } |
| | 138 | |
| | 139 | const url = pickAsset(data.assets ?? [], platform); |
| | 140 | if (url) { |
| | 141 | btn.href = url; |
| | 142 | btn.removeAttribute("target"); |
| | 143 | btn.removeAttribute("rel"); |
| | 144 | } |
| | 145 | } catch { |
| | 146 | btn.href = RELEASES_URL; |
| | 147 | } |
| | 148 | } |
| | 149 | |
| | 150 | init(); |
| | 151 | </script> |
| | 152 | |
| 67 | <style> | 153 | <style> |
| 68 | :root { | 154 | :root { |
| 69 | --bg: #09090b; | 155 | --bg: #09090b; |
| ... | @@ -198,7 +284,9 @@ | ... | @@ -198,7 +284,9 @@ |
| 198 | /* ── Hero button ── */ | 284 | /* ── Hero button ── */ |
| 199 | | 285 | |
| 200 | .hero-button { | 286 | .hero-button { |
| 201 | display: inline-block; | 287 | display: inline-flex; |
| | 288 | align-items: center; |
| | 289 | gap: 0.55rem; |
| 202 | background: #fafafa; | 290 | background: #fafafa; |
| 203 | color: #09090b; | 291 | color: #09090b; |
| 204 | padding: 0.75rem 2rem; | 292 | padding: 0.75rem 2rem; |
| ... | @@ -220,6 +308,25 @@ | ... | @@ -220,6 +308,25 @@ |
| 220 | transform: scale(0.98); | 308 | transform: scale(0.98); |
| 221 | } | 309 | } |
| 222 | | 310 | |
| | 311 | .hero-button-icon { |
| | 312 | display: none; |
| | 313 | width: 1em; |
| | 314 | height: 1em; |
| | 315 | flex-shrink: 0; |
| | 316 | } |
| | 317 | |
| | 318 | :global([data-platform="mac"]) .hero-button-icon--apple { |
| | 319 | display: block; |
| | 320 | } |
| | 321 | |
| | 322 | :global([data-platform="win"]) .hero-button-icon--windows { |
| | 323 | display: block; |
| | 324 | } |
| | 325 | |
| | 326 | :global([data-platform="linux"]) .hero-button-icon--linux { |
| | 327 | display: block; |
| | 328 | } |
| | 329 | |
| 223 | /* ── Screenshot ── */ | 330 | /* ── Screenshot ── */ |
| 224 | | 331 | |
| 225 | .screenshot-wrap { | 332 | .screenshot-wrap { |