Forráskód Böngészése

New UNA glyph for the default logo, favicon and powered-by badge (#5893)

* New UNA glyph for the default logo, favicon and powered-by badge

Default installs now use the UNA glyph (four ring segments and two balls,
segments at 40%) instead of the generic "SOCIAL" placeholder:

- Artificer's generic logo and mark: dark ink for light mode, white for
  dark mode. The logo pairs the glyph with the "una" lettering of the
  footer badge.
- favicon.svg switches to white under prefers-color-scheme: dark;
  apple-touch-icon.png is the glyph on white (iOS has no dark variant).
- The footer "Powered by UNA" badge draws in currentColor, so it takes
  the footer link colour in light and dark.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Switch the default favicon to white on dark browser tabs

Chrome kept the dark-ink favicon on a dark tab strip: it does not apply
the prefers-color-scheme rule inside the SVG. The default favicon now
comes with favicon-dark.svg (white ink), and a small head script swaps
the icon links on matchMedia('(prefers-color-scheme: dark)'), on load
and when the browser or OS switches. It follows the browser, not the
site's own colour scheme, since the icon only shows in tabs.

The icon tags move from PHP strings into template/meta_icons.html.
Studio keeps its own plate favicon (it reads on light and dark tabs) and
has no dark variant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Andrey Yasko 5 napja
szülő
commit
ccbd6a046d

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 0
install/sql/system.sql


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 4
modules/boonex/artificer/data/template/system/images/logo-dark-generic.svg


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 0 - 4
modules/boonex/artificer/data/template/system/images/logo-generic.svg


+ 1 - 19
modules/boonex/artificer/data/template/system/images/mark-dark-generic.svg

@@ -1,19 +1 @@
-<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
-<rect x="272" y="750" width="480" height="480" rx="240" transform="rotate(-90 272 750)" fill="url(#paint0_radial)"/>
-<path d="M779.401 690.055C763.149 680.672 742.59 685.529 730.231 699.651C709.823 722.97 685.301 743.388 656.977 759.748C534.977 830.214 383.064 801.903 293.774 699.618C281.426 685.474 260.849 680.595 244.589 689.983L141.228 749.658C123.426 759.936 117.748 783.124 130.179 799.494C274.252 989.211 540.303 1046.58 751.961 924.333C808.828 891.487 856.433 848.757 893.861 799.564C906.308 783.204 900.614 760.038 882.811 749.759L779.401 690.055Z" fill="url(#paint1_radial)"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M955.292 692.569C947.404 711.623 924.423 718.359 906.564 708.048L803.11 648.319C786.927 638.976 780.824 618.86 786.781 601.149C812.4 524.975 806.432 438.579 763.106 363.505C719.695 288.284 647.692 239.873 568.76 224.078C566.956 223.717 565.189 223.243 563.471 222.664C529.689 216.564 494.736 216.413 460.291 222.662C458.63 223.213 456.925 223.665 455.185 224.013C424.963 230.056 395.196 241.061 367.024 257.333C245.351 327.609 193.853 472.785 237.124 601.034C243.106 618.763 237.021 638.926 220.817 648.282L117.39 707.995C99.5511 718.294 76.5822 711.566 68.6672 692.548C2.33824 533.176 28.224 353.227 128.319 219.925C129.03 218.734 129.819 217.568 130.687 216.431C168.04 167.543 215.472 125.071 272.08 92.3884C483.604 -29.735 749.443 27.4341 893.619 216.742C894.709 218.173 895.673 219.651 896.514 221.166C907.665 236.137 918.063 251.917 927.623 268.482C1005.23 402.963 1010.42 559.392 955.292 692.569Z" fill="url(#paint2_radial)"/>
-<defs>
-<radialGradient id="paint0_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(752.223 990.248) rotate(-180) scale(480 732.283)">
-<stop stop-color="#FB923C"/>
-<stop offset="1" stop-color="#EA580C"/>
-</radialGradient>
-<radialGradient id="paint1_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(512.001 515) rotate(90) scale(474)">
-<stop stop-color="#F87171"/>
-<stop offset="1" stop-color="#EF4444"/>
-</radialGradient>
-<radialGradient id="paint2_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(512 -19.999) rotate(90) scale(544 2114.78)">
-<stop stop-color="#38BDF8"/>
-<stop offset="1" stop-color="#0284C7"/>
-</radialGradient>
-</defs>
-</svg>
+<svg width="512" height="512" viewBox="75 75 362 362" fill="none" xmlns="http://www.w3.org/2000/svg"><g fill="#fff"><path d="M322.4 324.2c1.4-1.3 3.8-.1 3.5 1.7-1 6-2 12-3.1 18-4.3 24.7-8.7 50-9.5 81.1-.1 1.6-1.1 3.1-2.6 3.5-17.3 5.5-35.7 8.5-54.7 8.5-22.1 0-43.2-4-62.8-11.3-2.5-.9-2.4-4.4-.1-5.5 24.6-11.8 42-37.5 43.7-66.2.1-2.4 2.3-4.2 4.7-3.9 4.7.8 9.6 1.1 14.5 1.1 25.8 0 49.3-10.3 66.4-27zM420.2 193.1c1.1-2.3 4.6-2.4 5.5.1 7.3 19.6 11.3 40.7 11.3 62.8 0 70.4-40.2 131.4-98.9 161.3-2.5 1.3-5.5-.7-5.3-3.5 1.4-24.4 5-45.3 8.8-66.6 4.7-27.3 9.6-55.3 9.6-91.2 0-4.9-.3-9.8-1.1-14.5-.3-2.4 1.5-4.6 3.9-4.7 28.7-1.7 54.4-19.1 66.2-43.7zM173.9 94.7c2.5-1.3 5.5.7 5.3 3.5-1.4 24.4-5 45.3-8.8 66.6-4.7 27.3-9.6 55.3-9.6 91.2 0 4.9.3 9.8 1.1 14.5.3 2.4-1.5 4.6-3.9 4.7-28.7 1.7-54.4 19.1-66.2 43.7-1.1 2.3-4.6 2.4-5.5-.1-7.3-19.6-11.3-40.7-11.3-62.8 0-70.4 40.2-131.4 98.9-161.3zM256 75c22.1 0 43.2 4 62.8 11.3 2.5.9 2.4 4.4.1 5.5-24.6 11.8-42 37.5-43.7 66.2-.1 2.4-2.3 4.2-4.7 3.9-4.7-.8-9.6-1.1-14.5-1.1-25.8 0-49.3 10.3-66.4 27-1.4 1.3-3.8.1-3.5-1.7 1-6 2-12 3.1-18 4.3-24.7 8.7-50 9.5-81.1.1-1.6 1.1-3.1 2.6-3.5 17.3-5.5 35.7-8.5 54.7-8.5z" fill-opacity=".4"/><circle cx="351.2" cy="160.8" r="57.1"/><circle cx="160.8" cy="351.2" r="57.1"/></g></svg>

+ 1 - 19
modules/boonex/artificer/data/template/system/images/mark-generic.svg

@@ -1,19 +1 @@
-<svg width="1024" height="1024" viewBox="0 0 1024 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
-<rect x="272" y="750" width="480" height="480" rx="240" transform="rotate(-90 272 750)" fill="url(#paint0_radial)"/>
-<path d="M779.401 690.055C763.149 680.672 742.59 685.529 730.231 699.651C709.823 722.97 685.301 743.388 656.977 759.748C534.977 830.214 383.064 801.903 293.774 699.618C281.426 685.474 260.849 680.595 244.589 689.983L141.228 749.658C123.426 759.936 117.748 783.124 130.179 799.494C274.252 989.211 540.303 1046.58 751.961 924.333C808.828 891.487 856.433 848.757 893.861 799.564C906.308 783.204 900.614 760.038 882.811 749.759L779.401 690.055Z" fill="url(#paint1_radial)"/>
-<path fill-rule="evenodd" clip-rule="evenodd" d="M955.292 692.569C947.404 711.623 924.423 718.359 906.564 708.048L803.11 648.319C786.927 638.976 780.824 618.86 786.781 601.149C812.4 524.975 806.432 438.579 763.106 363.505C719.695 288.284 647.692 239.873 568.76 224.078C566.956 223.717 565.189 223.243 563.471 222.664C529.689 216.564 494.736 216.413 460.291 222.662C458.63 223.213 456.925 223.665 455.185 224.013C424.963 230.056 395.196 241.061 367.024 257.333C245.351 327.609 193.853 472.785 237.124 601.034C243.106 618.763 237.021 638.926 220.817 648.282L117.39 707.995C99.5511 718.294 76.5822 711.566 68.6672 692.548C2.33824 533.176 28.224 353.227 128.319 219.925C129.03 218.734 129.819 217.568 130.687 216.431C168.04 167.543 215.472 125.071 272.08 92.3884C483.604 -29.735 749.443 27.4341 893.619 216.742C894.709 218.173 895.673 219.651 896.514 221.166C907.665 236.137 918.063 251.917 927.623 268.482C1005.23 402.963 1010.42 559.392 955.292 692.569Z" fill="url(#paint2_radial)"/>
-<defs>
-<radialGradient id="paint0_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(752.223 990.248) rotate(-180) scale(480 732.283)">
-<stop stop-color="#FB923C"/>
-<stop offset="1" stop-color="#EA580C"/>
-</radialGradient>
-<radialGradient id="paint1_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(512.001 515) rotate(90) scale(474)">
-<stop stop-color="#F87171"/>
-<stop offset="1" stop-color="#EF4444"/>
-</radialGradient>
-<radialGradient id="paint2_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(512 -19.999) rotate(90) scale(544 2114.78)">
-<stop stop-color="#38BDF8"/>
-<stop offset="1" stop-color="#0284C7"/>
-</radialGradient>
-</defs>
-</svg>
+<svg width="512" height="512" viewBox="75 75 362 362" fill="none" xmlns="http://www.w3.org/2000/svg"><g fill="#18181B"><path d="M322.4 324.2c1.4-1.3 3.8-.1 3.5 1.7-1 6-2 12-3.1 18-4.3 24.7-8.7 50-9.5 81.1-.1 1.6-1.1 3.1-2.6 3.5-17.3 5.5-35.7 8.5-54.7 8.5-22.1 0-43.2-4-62.8-11.3-2.5-.9-2.4-4.4-.1-5.5 24.6-11.8 42-37.5 43.7-66.2.1-2.4 2.3-4.2 4.7-3.9 4.7.8 9.6 1.1 14.5 1.1 25.8 0 49.3-10.3 66.4-27zM420.2 193.1c1.1-2.3 4.6-2.4 5.5.1 7.3 19.6 11.3 40.7 11.3 62.8 0 70.4-40.2 131.4-98.9 161.3-2.5 1.3-5.5-.7-5.3-3.5 1.4-24.4 5-45.3 8.8-66.6 4.7-27.3 9.6-55.3 9.6-91.2 0-4.9-.3-9.8-1.1-14.5-.3-2.4 1.5-4.6 3.9-4.7 28.7-1.7 54.4-19.1 66.2-43.7zM173.9 94.7c2.5-1.3 5.5.7 5.3 3.5-1.4 24.4-5 45.3-8.8 66.6-4.7 27.3-9.6 55.3-9.6 91.2 0 4.9.3 9.8 1.1 14.5.3 2.4-1.5 4.6-3.9 4.7-28.7 1.7-54.4 19.1-66.2 43.7-1.1 2.3-4.6 2.4-5.5-.1-7.3-19.6-11.3-40.7-11.3-62.8 0-70.4 40.2-131.4 98.9-161.3zM256 75c22.1 0 43.2 4 62.8 11.3 2.5.9 2.4 4.4.1 5.5-24.6 11.8-42 37.5-43.7 66.2-.1 2.4-2.3 4.2-4.7 3.9-4.7-.8-9.6-1.1-14.5-1.1-25.8 0-49.3 10.3-66.4 27-1.4 1.3-3.8.1-3.5-1.7 1-6 2-12 3.1-18 4.3-24.7 8.7-50 9.5-81.1.1-1.6 1.1-3.1 2.6-3.5 17.3-5.5 35.7-8.5 54.7-8.5z" fill-opacity=".4"/><circle cx="351.2" cy="160.8" r="57.1"/><circle cx="160.8" cy="351.2" r="57.1"/></g></svg>

+ 8 - 0
studio/template/scripts/BxBaseStudioFunctions.php

@@ -48,6 +48,14 @@ class BxBaseStudioFunctions extends BxBaseFunctions implements iBxDolSingleton
         return $GLOBALS['bxDolClasses']['BxBaseStudioFunctions'];
     }
 
+    /**
+     * Studio's favicon is the UNA logo on a coloured plate, which reads on light and dark tabs alike.
+     */
+    protected function getMetaIconDarkUrl()
+    {
+        return '';
+    }
+
     public function getLogo()
     {
         return bx_idn_to_utf8(BX_DOL_URL_ROOT, true);

BIN
template/images/icons/apple-touch-icon.png


+ 1 - 0
template/images/icons/favicon-dark.svg

@@ -0,0 +1 @@
+<svg width="32" height="32" viewBox="65 65 382 382" fill="none" xmlns="http://www.w3.org/2000/svg"><g fill="#fff"><path d="M322.4 324.2c1.4-1.3 3.8-.1 3.5 1.7-1 6-2 12-3.1 18-4.3 24.7-8.7 50-9.5 81.1-.1 1.6-1.1 3.1-2.6 3.5-17.3 5.5-35.7 8.5-54.7 8.5-22.1 0-43.2-4-62.8-11.3-2.5-.9-2.4-4.4-.1-5.5 24.6-11.8 42-37.5 43.7-66.2.1-2.4 2.3-4.2 4.7-3.9 4.7.8 9.6 1.1 14.5 1.1 25.8 0 49.3-10.3 66.4-27zM420.2 193.1c1.1-2.3 4.6-2.4 5.5.1 7.3 19.6 11.3 40.7 11.3 62.8 0 70.4-40.2 131.4-98.9 161.3-2.5 1.3-5.5-.7-5.3-3.5 1.4-24.4 5-45.3 8.8-66.6 4.7-27.3 9.6-55.3 9.6-91.2 0-4.9-.3-9.8-1.1-14.5-.3-2.4 1.5-4.6 3.9-4.7 28.7-1.7 54.4-19.1 66.2-43.7zM173.9 94.7c2.5-1.3 5.5.7 5.3 3.5-1.4 24.4-5 45.3-8.8 66.6-4.7 27.3-9.6 55.3-9.6 91.2 0 4.9.3 9.8 1.1 14.5.3 2.4-1.5 4.6-3.9 4.7-28.7 1.7-54.4 19.1-66.2 43.7-1.1 2.3-4.6 2.4-5.5-.1-7.3-19.6-11.3-40.7-11.3-62.8 0-70.4 40.2-131.4 98.9-161.3zM256 75c22.1 0 43.2 4 62.8 11.3 2.5.9 2.4 4.4.1 5.5-24.6 11.8-42 37.5-43.7 66.2-.1 2.4-2.3 4.2-4.7 3.9-4.7-.8-9.6-1.1-14.5-1.1-25.8 0-49.3 10.3-66.4 27-1.4 1.3-3.8.1-3.5-1.7 1-6 2-12 3.1-18 4.3-24.7 8.7-50 9.5-81.1.1-1.6 1.1-3.1 2.6-3.5 17.3-5.5 35.7-8.5 54.7-8.5z" fill-opacity=".4"/><circle cx="351.2" cy="160.8" r="57.1"/><circle cx="160.8" cy="351.2" r="57.1"/></g></svg>

+ 1 - 9
template/images/icons/favicon.svg

@@ -1,9 +1 @@
-<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
-<rect x="0.75" y="0.75" width="22.5" height="22.5" rx="3.25" fill="white" stroke="#555555" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M19.3271 9.93627C19.9854 10.5946 19.9854 11.662 19.3271 12.3204C18.6687 12.9788 17.6013 12.9788 16.943 12.3204C16.2846 11.662 16.2846 10.5946 16.943 9.93627C17.6013 9.27791 18.6687 9.27791 19.3271 9.93627" stroke="#323232" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M13.8355 6.92697C14.8492 7.9407 14.8492 9.58429 13.8355 10.598C12.8218 11.6118 11.1782 11.6118 10.1644 10.598C9.1507 9.5843 9.1507 7.94071 10.1644 6.92697C11.1782 5.91323 12.8218 5.91323 13.8355 6.92697" stroke="#323232" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M7.05707 9.93627C7.71543 10.5946 7.71543 11.662 7.05707 12.3204C6.39871 12.9788 5.3313 12.9788 4.67294 12.3204C4.01458 11.662 4.01458 10.5946 4.67294 9.93627C5.3313 9.27791 6.39871 9.27791 7.05707 9.93627" stroke="#323232" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M21.1667 17.8333V16.92C21.1667 15.7692 20.2342 14.8367 19.0833 14.8367H18.4158" stroke="#323232" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M2.83333 17.8333V16.92C2.83333 15.7692 3.76583 14.8367 4.91667 14.8367H5.58417" stroke="#323232" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
-<path d="M16.4492 17.8333V16.4992C16.4492 14.8883 15.1433 13.5825 13.5325 13.5825H10.4667C8.85583 13.5825 7.55 14.8883 7.55 16.4992V17.8333" stroke="#323232" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
-</svg>
+<svg width="32" height="32" viewBox="65 65 382 382" fill="none" xmlns="http://www.w3.org/2000/svg"><style>g{fill:#18181B}@media (prefers-color-scheme:dark){g{fill:#fff}}</style><g><path d="M322.4 324.2c1.4-1.3 3.8-.1 3.5 1.7-1 6-2 12-3.1 18-4.3 24.7-8.7 50-9.5 81.1-.1 1.6-1.1 3.1-2.6 3.5-17.3 5.5-35.7 8.5-54.7 8.5-22.1 0-43.2-4-62.8-11.3-2.5-.9-2.4-4.4-.1-5.5 24.6-11.8 42-37.5 43.7-66.2.1-2.4 2.3-4.2 4.7-3.9 4.7.8 9.6 1.1 14.5 1.1 25.8 0 49.3-10.3 66.4-27zM420.2 193.1c1.1-2.3 4.6-2.4 5.5.1 7.3 19.6 11.3 40.7 11.3 62.8 0 70.4-40.2 131.4-98.9 161.3-2.5 1.3-5.5-.7-5.3-3.5 1.4-24.4 5-45.3 8.8-66.6 4.7-27.3 9.6-55.3 9.6-91.2 0-4.9-.3-9.8-1.1-14.5-.3-2.4 1.5-4.6 3.9-4.7 28.7-1.7 54.4-19.1 66.2-43.7zM173.9 94.7c2.5-1.3 5.5.7 5.3 3.5-1.4 24.4-5 45.3-8.8 66.6-4.7 27.3-9.6 55.3-9.6 91.2 0 4.9.3 9.8 1.1 14.5.3 2.4-1.5 4.6-3.9 4.7-28.7 1.7-54.4 19.1-66.2 43.7-1.1 2.3-4.6 2.4-5.5-.1-7.3-19.6-11.3-40.7-11.3-62.8 0-70.4 40.2-131.4 98.9-161.3zM256 75c22.1 0 43.2 4 62.8 11.3 2.5.9 2.4 4.4.1 5.5-24.6 11.8-42 37.5-43.7 66.2-.1 2.4-2.3 4.2-4.7 3.9-4.7-.8-9.6-1.1-14.5-1.1-25.8 0-49.3 10.3-66.4 27-1.4 1.3-3.8.1-3.5-1.7 1-6 2-12 3.1-18 4.3-24.7 8.7-50 9.5-81.1.1-1.6 1.1-3.1 2.6-3.5 17.3-5.5 35.7-8.5 54.7-8.5z" fill-opacity=".4"/><circle cx="351.2" cy="160.8" r="57.1"/><circle cx="160.8" cy="351.2" r="57.1"/></g></svg>

+ 25 - 0
template/meta_icons.html

@@ -0,0 +1,25 @@
+<bx_if:icon_fav><link rel="icon" href="__url__" sizes="any" /></bx_if:icon_fav>
+<bx_if:icon_svg><link rel="icon" href="__url__" type="image/svg+xml" /></bx_if:icon_svg>
+<bx_if:icon_dark>
+<link rel="icon" href="__url__" sizes="any" data-bx-icon-light="__url__" data-bx-icon-dark="__url_dark__" />
+<link rel="icon" href="__url__" type="image/svg+xml" data-bx-icon-light="__url__" data-bx-icon-dark="__url_dark__" />
+<script>
+    /* Browser tabs follow the browser/OS colour scheme, so the favicon does too, not the site's own colour scheme. */
+    (function () {
+        var oMedia = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)');
+        if (!oMedia)
+            return;
+
+        var fUpdate = function () {
+            document.querySelectorAll('link[data-bx-icon-dark]').forEach(function (oLink) {
+                oLink.href = oLink.getAttribute(oMedia.matches ? 'data-bx-icon-dark' : 'data-bx-icon-light');
+            });
+        };
+
+        fUpdate();
+        if (oMedia.addEventListener)
+            oMedia.addEventListener('change', fUpdate);
+    })();
+</script>
+</bx_if:icon_dark>
+<link rel="apple-touch-icon" href="__url_apple__" />

+ 32 - 12
template/scripts/BxBaseFunctions.php

@@ -750,8 +750,13 @@ class BxBaseFunctions extends BxDolFactory implements iBxDolSingleton
         if(($iId = (int)getParam('sys_site_icon_svg')) != 0)
             $sImageUrlSvg = BxDolStorage::getObjectInstance(BX_DOL_STORAGE_OBJ_IMAGES)->getFileUrlById($iId);
 
-        if(empty($sImageUrlFav) && empty($sImageUrlSvg))
+        // default icon, with a dark variant for a dark browser/OS colour scheme when the template has one
+        $sImageUrlDark = '';
+        if(empty($sImageUrlFav) && empty($sImageUrlSvg)) {
             $sImageUrlFav = $sImageUrlSvg = $this->_oTemplate->getIconUrl('favicon.svg');
+            $sImageUrlDark = $this->getMetaIconDarkUrl();
+        }
+        $bImageDark = !empty($sImageUrlDark);
 
         // apple device icon
         $sImageUrlApl = '';
@@ -773,18 +778,33 @@ class BxBaseFunctions extends BxDolFactory implements iBxDolSingleton
             $sImageUrlFcb = $this->_oTemplate->getIconUrl('facebook-icon.png');
 */
 
-        $sRet = '';
-        if($sImageUrlFav)
-            $sRet .= '<link rel="icon" href="' . $sImageUrlFav . '" sizes="any" />';
-        if($sImageUrlSvg)
-            $sRet .= '<link rel="icon" href="' . $sImageUrlSvg . '" type="image/svg+xml" />';
-        $sRet .= '<link rel="apple-touch-icon" href="' . $sImageUrlApl . '" />';
-
-/*
-        $sRet .= '<link rel="image_src" sizes="100x100" href="' . $sImageUrlFcb . '" />';
-*/
+        return $this->_oTemplate->parseHtmlByName('meta_icons.html', [
+            'bx_if:icon_fav' => [
+                'condition' => !$bImageDark && !empty($sImageUrlFav),
+                'content' => ['url' => bx_html_attribute($sImageUrlFav)]
+            ],
+            'bx_if:icon_svg' => [
+                'condition' => !$bImageDark && !empty($sImageUrlSvg),
+                'content' => ['url' => bx_html_attribute($sImageUrlSvg)]
+            ],
+            'bx_if:icon_dark' => [
+                'condition' => $bImageDark,
+                'content' => [
+                    'url' => bx_html_attribute($sImageUrlSvg),
+                    'url_dark' => bx_html_attribute($sImageUrlDark)
+                ]
+            ],
+            'url_apple' => bx_html_attribute($sImageUrlApl),
+        ]);
+    }
 
-        return $sRet;
+    /**
+     * Default favicon for a dark browser/OS colour scheme (browser tabs follow it, not the site's own colour scheme).
+     * @return string URL, or an empty string when the default favicon has no dark variant.
+     */
+    protected function getMetaIconDarkUrl()
+    {
+        return $this->_oTemplate->getIconUrl('favicon-dark.svg');
     }
 
     function getInjectionHead() 

+ 9 - 0
tests/units/install/SystemSqlDefaultsTest.php

@@ -23,4 +23,13 @@ class SystemSqlDefaultsTest extends \PHPUnit\Framework\TestCase
         $this->assertSame(1, $bFound, 'system.sql adds the create-post block to the home page.');
         $this->assertSame(0, (int)$aMatch[1], 'It shows only its form: the content-only design box (BX_DB_CONTENT_ONLY).');
     }
+
+    public function testPoweredByBadgeFollowsTheFooterColour(): void
+    {
+        $bFound = preg_match("/\\('sys_footer', 'system', 'powered_by', [^\\n]*?'_blank', '(<svg.*?<\\/svg>)'/", self::systemSql(), $aMatch);
+
+        $this->assertSame(1, $bFound, 'system.sql adds the powered-by badge to the footer menu.');
+        $this->assertStringContainsString('fill="currentColor"', $aMatch[1], 'The badge draws in the footer link colour, so it reads in light and dark.');
+        $this->assertDoesNotMatchRegularExpression('/(fill|stroke)="#/', $aMatch[1], 'No fixed colour that would vanish on one of the two schemes.');
+    }
 }

+ 62 - 0
tests/units/template/scripts/BxBaseMetaIconsTest.php

@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * Favicon tags in the page head. Browser tabs follow the browser/OS colour scheme, so the default favicon has a
+ * dark variant that the head script swaps in; Studio's favicon is a coloured plate and has none.
+ */
+class BxBaseMetaIconsTest extends BxDolTestCase
+{
+    private function withOptions(array $aOptions, callable $fTest)
+    {
+        $aPrior = [];
+        foreach ($aOptions as $sName => $sValue) {
+            $aPrior[$sName] = getParam($sName);
+            setParam($sName, $sValue);
+        }
+
+        try {
+            return $fTest();
+        }
+        finally {
+            foreach ($aPrior as $sName => $sValue)
+                setParam($sName, $sValue);
+        }
+    }
+
+    private function withDefaultIcons(callable $fTest)
+    {
+        return $this->withOptions(['sys_site_icon' => '0', 'sys_site_icon_svg' => '0'], $fTest);
+    }
+
+    public function testDefaultFaviconSwitchesWithTheBrowserScheme(): void
+    {
+        $sHtml = $this->withDefaultIcons(fn() => BxTemplFunctions::getInstance()->getMetaIcons());
+
+        $this->assertMatchesRegularExpression('/<link rel="icon" href="[^"]*\/favicon\.svg" sizes="any" data-bx-icon-light="[^"]*\/favicon\.svg" data-bx-icon-dark="[^"]*\/favicon-dark\.svg" \/>/', $sHtml);
+        $this->assertMatchesRegularExpression('/<link rel="icon" href="[^"]*\/favicon\.svg" type="image\/svg\+xml" data-bx-icon-light="[^"]*" data-bx-icon-dark="[^"]*\/favicon-dark\.svg" \/>/', $sHtml);
+        $this->assertStringContainsString("matchMedia('(prefers-color-scheme: dark)')", $sHtml);
+        $this->assertStringContainsString('<link rel="apple-touch-icon" href="', $sHtml);
+    }
+
+    public function testDefaultFaviconFilesAreDarkAndLightInk(): void
+    {
+        $sDir = BX_DIRECTORY_PATH_ROOT . 'template/images/icons/';
+
+        $sLight = file_get_contents($sDir . 'favicon.svg');
+        $this->assertStringContainsString('g{fill:#18181B}', $sLight, 'Dark ink on light tabs.');
+        $this->assertStringContainsString('@media (prefers-color-scheme:dark){g{fill:#fff}}', $sLight, 'Browsers that read the SVG\'s own media query switch without the script.');
+
+        $sDark = file_get_contents($sDir . 'favicon-dark.svg');
+        $this->assertStringContainsString('<g fill="#fff">', $sDark, 'White ink on dark tabs, with no media query left for the browser to ignore.');
+        $this->assertStringNotContainsString('@media', $sDark);
+    }
+
+    public function testStudioKeepsItsOwnFaviconInDarkMode(): void
+    {
+        $sHtml = $this->withDefaultIcons(fn() => BxTemplStudioFunctions::getInstance()->getMetaIcons());
+
+        $this->assertStringContainsString('studio/template/images/icons/favicon.svg', $sHtml);
+        $this->assertStringNotContainsString('data-bx-icon-dark', $sHtml);
+        $this->assertStringNotContainsString('favicon-dark.svg', $sHtml);
+    }
+}

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott