From 26051e54c9ce135b0186acd25f6edb570c220e5b Mon Sep 17 00:00:00 2001 From: Kevin Longe <273747162+kvlonge@users.noreply.github.com> Date: Sun, 1 Nov 2026 05:54:32 +0000 Subject: [PATCH] Make favicons transparent and simplify hero actions --- README.md | 12 +++++++----- assets/favicon-16.png | Bin 610 -> 396 bytes assets/favicon-32.png | Bin 1416 -> 918 bytes assets/favicon-dark-32.png | Bin 0 -> 903 bytes favicon.ico | Bin 5166 -> 3263 bytes index.html | 5 +---- styles.css | 8 -------- tests/website.spec.mjs | 31 ++++++++++++++++++++++++++++++- theme.js | 4 +++- 9 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 assets/favicon-dark-32.png diff --git a/README.md b/README.md index 5946185..9a3f020 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ light/dark preference in the browser. Without JavaScript, the page remains usabl ## Checks Browser tests cover theme selection and persistence, keyboard navigation, responsive layouts, -product statuses, sharing metadata and image dimensions. They require Node.js and Python 3: +product statuses, sharing metadata, image dimensions and favicon transparency. They require Node.js and Python 3: ```sh npm ci @@ -35,13 +35,15 @@ publishing or deployment step. ## Sharing assets -`favicon.ico` contains 16px, 32px and 48px icons. PNG favicons and a 180px Apple touch icon use the -original SQLStack mark on white backing for legibility in light and dark browser chrome. +`favicon.ico` contains transparent 16px, 32px and 48px icons. The PNG favicons preserve the same +original SQLStack mark without its former white backing. The existing theme script selects a white +variant for dark browser chrome using the system preference, independently of the page's theme +override. The 180px Apple home-screen icon retains its opaque background. `assets/og-sqlstack-dark.png` is an opaque 1200 × 630 sharing card using the original SQLStack wordmark and the site's Inter typography on a near-black background. Its branding and text fit inside the central 630px square so small thumbnail crops retain the complete message. The previous -`assets/og-sqlstack.png` remains available for cached metadata. These are raster derivatives, not -replacement logos or SVG originals. +`assets/og-sqlstack.png` remains available for cached metadata. These use the original raster artwork, +not replacement logos or SVG originals. Canonical and Open Graph/Twitter URLs target `https://sqlstack.io/`. Local previews can verify the metadata and assets, but public social-crawler validation requires a separately authorized deployment. diff --git a/assets/favicon-16.png b/assets/favicon-16.png index c63a40ab80f0a0cf55515bd5cc8a540bdf26059a..cca1cc995174b704eb0240a44791ee3d87e1145e 100644 GIT binary patch delta 380 zcmV-?0fYYH1dIca8Gi-<001BJ|6u?C0aHmtK~#9!#nU}V98nYn;BRIvOw5ADLWqH& z!6ua=qznWF!76B*CT%J)g_Vt9V`G)d!a`ZWK*}^0LGY(jB!LJjf<Wjo^)jW=~p=}Eb@?w|?#=)%i5Jx?&lDHbu0f2h?<$k2?> zSPciyV?PSw@7Tlmj$2f+B*u1ZqZ3=<=5N?<3ukZR-yuxnbyK_;j7~4%6Z+75Phu4VEc~=?M2_4b2yyC`Ebq`i3m0$2Ahhm)qhB2YU=UQ^80A?ODdh* zmS13Z*jk#KdV9{B%_Vv#5)tQ|G4|x?GvB}sIUxhkUrs~>K-+HX=*WGC!;XmTPZa{g zBR>=+FK>$|2nJCUMbRLNq97nbEWWn5w5+!=ohSP%>+8Sba@DD-s&TGy&N3fZHpUq+|F&7&QhJ>QT<7@9076I|$yiA+P&U; zf#GoYV>tXNcR~c>yyZ}HU(dPQgF_9j`W%w`=<)9E&VLJiy}{YJ7t_;U*T3r#-DF+fI2(&E{k>B`b<7%O6%&-h>vSu^1v7 zy5sNYXv=N5c5C9M$R#om9c@WrDQNb8v0C0W4=c=y*Kp-L_ zP1Aq~h)n>Zv74ZwgQyFYR85E0000HzT=T(5{Iz5$mGB+R6ddR~vJ z+}rOQleJ~t)AQY8awm5uE9ZP??Y-B3uk~MR?XNn1<;fOv^nWb!SOPG12z?*Jcs~Lg za5>JwYOKI=H24GG;~RX2ckn6dSYO4wd81l@guPh261U?#7Jua}IDpyU%Kss3KZWwT^j<9lpeT2Rz7VnbkH(v{u7|h7cz+(kjt~@J z9|yxPNv<8HIJe{8Bz`nusDx!Fwk1#w6@n^Ab3fK$2WDb^FS)iY`TK07;?=R&*3fSZ zUX9Fx5~ufrIJaSdBf}dTaV}28GEBs&_D3DqjSs?u-+$r?Y{wkd;#RD}L!$~&;lKlJR;D5O|{Y2V$81sfn%I~>kcr4^|Y{K1mDnR^-N4fy4#eGq~;Wbx0ajBE0>sH2eZ*$L3QJuU#D^EiJeosW*e)Lw~ml*GA5-OGNw`kK>6%^iBYit#Ubt zVzL{1@B{uz_k$I|nGNBoHOXi(RI2DcoD_inY0Eharg2sxWG^;8Kb6$kM9A@0SuS%9 zw5nqP@o1{1br%P=r^Qt&E_Lbw6CvXX=rGNz<4`4I3W#ST1if}s%gty{xc92qpl+R{ z>3@){&!9^P_u~OPIO5hc4?rIu;!j+b?f`Y`Ue|71bt?p=5beOtkM2?~NKT9p0M`w`YFU3*B0( hrN3rN02Uj--)d(4h!KG}WB>pF07*qoL^bFVmi%)rlC%jnZt5*5COTF zHnO4^tgNu-oVOom*_KO}KmMrc{qfDt`Od!2d!F|>&--BjKz|Q12ztQr?+0Lmt_mS2 zr3fL1!%F%0RYC> zGZh}#WGN*fq_ws6KwkbgMJMX&>)m@iH@g!NLZYKbE=omx^xeehv= z`<=V$Eg=MBEPthRW8mHZ0JV-Wo|-ge+m5n zQjD>Xa$)NH4WFbd4hCtmf<1J&kW!}6Xt)snB)h5%02s!nzAIMQ-F1_G{2+uz$Hq!2 zrIf0!zs-&@rj%lYIKcS$ctVH}V(=aS000m|K1yG|eSgO;gfU3T7#rAOPnJ377!!n1 z%JgYlwq!BJlmZ8*2mlTje)Zm(mBpuy&rDAC)%!{*g_J_bej$WZYZ{HlVi{MMpSN}E z#)88~gpe06mN*=aK~A9Pn>FW!j=R5QWoDSoqdM*Ok`n9B7fY(Et8J||`@OCn-a`oW z(rN<&{C^`%rntBt>|7rF6>mFk4O!2pe3JP1UU0e0;+keoaf^!Z4i(XzD zGVJjngK^*z;)z;Q=r_*zf5K{f_=;$adE6?1xd3?f@V1qGaSlG1W6e;DQg2E?; zN2)!npV}Ob`v5=)CWw|;ORc440O038G$0_*5Pur%H`Gr2#_* zlz&n}2&I%#!U$mmGeQ`nj4_Nc7g7ij6%|>Kf8gWvv~_9e8#ibB_~_qSvAhpJ_2tXk zvbRT@%?P2SDT(`YcSV>?N<2acA%v>Y$+?pYE(8}sUHkZPak+bT7N0EA>-9;~p4+{5 zpSMn%lf5Y{%-Dyby}A1lLI?5=PMlz&lz&c6m=rg5O!4V6MaNIpT&c0$v~}3+N^L$q z-j4aDUE~ z8dbRN!KBGkYwPNIZ#g!bM_S^?g_}$vA;Errep>Cr2$19c{kFEY#>S@d$||eXdi83f zx|m9S03apkbYA7w3wpiYZQ3r1q9P-%)YhqPODQWVDl03i01$xGXfzlh0B~~dvgqD} zyX{s=NeKZAE8cuVuh$Rarc0JAWPg-MDHSpygb+e0!5BN8&K{@J$+?23gizuNE(8Ej zN~M%S!h-oPE_>}&DW#`Hx&UILqt~on2?#5*0{|r+H<$`3rP7be(wka(dFj@zUGrJS zdiNme@20BhIbZJFkdetbcYC#Jl&2f^n_`sG8OhUEEMGQ!_)`k?PiL|su6gRxr7v=J zoGd=w?dW!ybnnAu(8?JABE!QI6BB05Oo@mvd44DKpB4j0CPJv8vFY5oA4<#0>l+$v zH*H;AU6_y|K0|^6{lmh-A|oTlj(H|3GD54>s>)P*1|LWNe>(p60e%O2ic!vao6N-k O0000fqQ`4fvvzaumKSG3pfLu2EGH1178D8ysv_8^i#*JUi@C89#(%) zhia2n`Q^KT`lb4K;#rk)#tCl;A5+g1f(L3HXZd`X?gqvAN9t7YttKhZkKg+flcj>` zzg@Mu7;oP!Jd4^1!ZuEOfdQ}-SouGI?Z>+Ycqr|w<+7l?{3`BSApX~iWqQ{GJ`Lgh zNg%9}n_f+EG+bJzIF~Emo8BH#FHhl}2*SSlgt|tZQQuSl=m1{VYH1eLW9lAto%)Qr zR^6?xZ)H^-y`YWLXTT<4A20`80o)Dj2JQf^2Bv_u;p&S~2TlQ>11EuBfIYw)Kn=_Q zPXb$jgX2Qby6I>_{t5M2_2%$ONuQCuQQfW{irUe7~n`vUR|fz;(b?;Vpx{4&WV&v!{dpA0TY4cvRh_ei+(c3Q#RA6YpVB9hU+F zEzRq}`*3*mopB(1S$#3~4~O8U1O0VUs!jqI3+295?+t#h#o0Oa`Yr`#g82jK>_K(D z!$LduttV>rco=|sr#ctB7YhC(3cMXeM~i%&QXf&@SASH`7s~vp{-l1aKBZn8?`G8x z673i2jsoZ-3d|>KK2dj$sS(raR&|@YS>2HCwy68nZ<1FU^{o0r2p%a$xem+&w-n`a zF8cZ@;8);x;8L0orhyw`PS^$9l+fR1R28-50Ppo+%S z_KVAciRrA02G&cfRpO-(-b+KuNC>tEnsaJp#CHuKgOmw__#3Al=BMSJc}&4C`E7-7rtW+kpFk9l(vL12(`y^n{-Sz$fDOVlnJA%S|oS>R+=} d1y)*tzX2n{{9y-ZFBSj*002ovPDHLkV1oK=v-bc1 literal 0 HcmV?d00001 diff --git a/favicon.ico b/favicon.ico index 4db19045924c38eebd1069d7af0962f1d1821056..371fee3d1ce3f59500d468035a39d6bd2baf3abf 100644 GIT binary patch literal 3263 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 R;+tzb=D0cp^MBv9{{TJ^4U+%> literal 5166 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 diff --git a/index.html b/index.html index 49c0852..34cea79 100644 --- a/index.html +++ b/index.html @@ -22,9 +22,7 @@ - - - + @@ -58,7 +56,6 @@

Your data stack. Engineered to change.Rust-backed SQL and Python tools for data engineers.

Compile-time checks, tested behaviour and enforceable architecture.

diff --git a/styles.css b/styles.css index c7ace19..ecfe6f2 100644 --- a/styles.css +++ b/styles.css @@ -25,9 +25,6 @@ --focus: #1768ba; --button-border: #bdc9da; --button-hover: #f3f6fa; - --primary: #0866db; - --primary-ink: #ffffff; - --primary-hover: #0755b7; --gold-ink: #765600; --gold-bg: #fff3cb; --pink-ink: #a52138; @@ -50,9 +47,6 @@ --focus: #75b5ff; --button-border: #626a76; --button-hover: #171a1f; - --primary: #3788e8; - --primary-ink: #0d0f12; - --primary-hover: #66a6f0; --gold-ink: #ffe07a; --gold-bg: #352b12; --pink-ink: #ffacba; @@ -99,8 +93,6 @@ h1 span { display: block; } .hero-actions { display: flex; justify-content: center; flex-wrap: wrap; gap: 12px; margin-top: 20px; } .button { display: inline-flex; align-items: center; justify-content: center; gap: 8px; padding: 14px 20px; min-height: 48px; border: 1px solid var(--button-border); border-radius: 2px; color: var(--ink); font-size: 14px; line-height: 20px; text-decoration: none; } .button:hover { background: var(--button-hover); text-decoration: none; } -.button.primary { color: var(--primary-ink); background: var(--primary); border-color: var(--primary); } -.button.primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); } .tool-row { display: grid; grid-template-columns: 304px minmax(0, 1fr); gap: 24px; border-top: 1px solid var(--line); padding: 18px 0 16px; } .category { padding-top: 8px; } .category .eyebrow { margin: 0 0 8px; color: var(--muted); font-size: 14px; line-height: 20px; text-transform: uppercase; } diff --git a/tests/website.spec.mjs b/tests/website.spec.mjs index 26b7b91..97816e4 100644 --- a/tests/website.spec.mjs +++ b/tests/website.spec.mjs @@ -8,9 +8,11 @@ for (const system of ['light', 'dark']) { const toggle = page.getByRole('button', { name: 'Dark mode', exact: true }); await expect(page.locator('html')).toHaveCSS('color-scheme', system); await expect(toggle).toHaveAttribute('aria-pressed', String(system === 'dark')); + await expect(page.locator('[data-favicon]')).toHaveAttribute('href', `assets/favicon${system === 'dark' ? '-dark' : ''}-32.png?v=2`); await page.emulateMedia({ colorScheme: other }); await expect(page.locator('html')).toHaveCSS('color-scheme', other); + await expect(page.locator('[data-favicon]')).toHaveAttribute('href', `assets/favicon${other === 'dark' ? '-dark' : ''}-32.png?v=2`); await page.emulateMedia({ colorScheme: system }); await expect(page.locator('html')).toHaveCSS('color-scheme', system); @@ -24,6 +26,7 @@ for (const system of ['light', 'dark']) { await page.emulateMedia({ colorScheme: system }); await expect(page.locator('html')).toHaveCSS('color-scheme', other); await expect(page.locator('meta[name="theme-color"]')).toHaveAttribute('content', other === 'dark' ? '#0d0f12' : '#ffffff'); + await expect(page.locator('[data-favicon]')).toHaveAttribute('href', `assets/favicon${system === 'dark' ? '-dark' : ''}-32.png?v=2`); }); } @@ -59,7 +62,11 @@ test('approved products, sharing assets and responsive navigation work in both t expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true); await expect(page.getByRole('button', { name: 'Dark mode', exact: true })).toBeInViewport(); } - await page.getByRole('link', { name: 'Find a tool', exact: false }).click(); + await expect(page.locator('.hero').getByRole('link')).toHaveCount(1); + await expect(page.locator('.hero').getByRole('link')).toHaveAccessibleName('View on GitHub'); + await expect(page.locator('.hero').getByRole('link')).toHaveAttribute('href', 'https://github.com/sqlstack-io/sqlstack'); + await page.getByRole('link', { name: 'Skip to tools', exact: true }).focus(); + await page.keyboard.press('Enter'); await expect(page).toHaveURL(/#tools$/); await page.keyboard.press('Tab'); await expect(page.getByRole('link', { name: 'SQLBuild website', exact: true })).toBeFocused(); @@ -75,6 +82,7 @@ test('approved products, sharing assets and responsive navigation work in both t ['/assets/og-sqlstack-dark.png', 1200, 630], ['/assets/favicon-16.png', 16, 16], ['/assets/favicon-32.png', 32, 32], + ['/assets/favicon-dark-32.png', 32, 32], ['/assets/apple-touch-icon.png', 180, 180], ]) { const response = await request.get(path); @@ -90,4 +98,25 @@ test('approved products, sharing assets and responsive navigation work in both t expect(ico.readUInt16LE(2)).toBe(1); expect(ico.readUInt16LE(4)).toBe(3); expect([ico[6], ico[22], ico[38]]).toEqual([16, 32, 48]); + + for (const path of ['/assets/favicon-16.png', '/assets/favicon-32.png', '/assets/favicon-dark-32.png', '/favicon.ico']) { + const pixels = await page.evaluate(async (src) => { + const image = new Image(); + image.src = src; + await image.decode(); + const canvas = document.createElement('canvas'); + canvas.width = image.naturalWidth; + canvas.height = image.naturalHeight; + const context = canvas.getContext('2d'); + context.drawImage(image, 0, 0); + const data = context.getImageData(0, 0, canvas.width, canvas.height).data; + const corners = [0, canvas.width - 1, canvas.width * (canvas.height - 1), canvas.width * canvas.height - 1]; + return { + corners: corners.map((pixel) => data[pixel * 4 + 3]), + opaquePixels: Array.from(data).filter((value, index) => index % 4 === 3 && value === 255).length, + }; + }, path); + expect(pixels.corners, path).toEqual([0, 0, 0, 0]); + expect(pixels.opaquePixels, path).toBeGreaterThan(0); + } }); diff --git a/theme.js b/theme.js index 4d4ae7b..1aba173 100644 --- a/theme.js +++ b/theme.js @@ -13,6 +13,8 @@ function apply(theme) { root.dataset.theme = theme; document.querySelector('meta[name="theme-color"]').content = theme === 'dark' ? '#0d0f12' : '#ffffff'; + // Match browser chrome, even when the page theme is explicitly overridden. + document.querySelector('[data-favicon]').href = system.matches ? 'assets/favicon-dark-32.png?v=2' : 'assets/favicon-32.png?v=2'; const toggle = document.querySelector('[data-theme-toggle]'); if (toggle) { toggle.setAttribute('aria-pressed', String(theme === 'dark')); @@ -23,7 +25,7 @@ apply(preference || (system.matches ? 'dark' : 'light')); system.addEventListener('change', () => { - if (!preference) apply(system.matches ? 'dark' : 'light'); + apply(preference || (system.matches ? 'dark' : 'light')); }); document.addEventListener('DOMContentLoaded', () => {