feat(workbench): add optional workspace logos and color badges to browser tabs (#11035)

* feat: add optional workspace favicon and identification color

Signed-off-by: Ratel-pwn <2448574643@qq.com>

* refactor: simplify workspace identification color control

Signed-off-by: Ratel-pwn <2448574643@qq.com>

* fix: preserve logo size when overlaying favicon color

Signed-off-by: Ratel-pwn <2448574643@qq.com>

* fix(workbench): separate favicon badge with a transparent cutout

Signed-off-by: Ratel-pwn <2448574643@qq.com>

* fix(workbench): restore workspace favicon before app startup

Signed-off-by: Ratel-pwn <2448574643@qq.com>

---------

Signed-off-by: Ratel-pwn <2448574643@qq.com>
This commit is contained in:
DawnRatel
2026-09-25 11:00:19 +02:00
committed by GitHub
parent 5eb50ee39b
commit bda10fa45e
26 changed files with 670 additions and 7 deletions
+27 -2
View File
@@ -4,10 +4,35 @@
<head>
<meta charset="utf8">
<title>Huly</title>
<link rel="shortcut icon" href="/huly/favicon.ico" sizes="any" id="default-favicon">
<link rel="shortcut icon" data-default-href="/huly/favicon.ico" sizes="any" id="default-favicon">
<script id="workspace-favicon-bootstrap">
// Run before the application (and before assigning a fallback URL) during tab restoration.
// Keep the cache key and PNG validation in sync with presentation/workspaceIdentity.ts.
;(function () {
var fallback = document.getElementById('default-favicon')
try {
var workspace = location.pathname.match(/^\/workbench\/[^/]+/)
var icon = workspace && localStorage.getItem('huly.workspace-favicon:' + workspace[0])
if (icon && icon.length <= 16384 && /^data:image\/png;base64,[A-Za-z0-9+/]+=*$/.test(icon)) {
var link = document.createElement('link')
link.id = 'workspace-favicon'
link.rel = 'icon'
link.type = 'image/png'
link.sizes = '32x32'
link.href = icon
document.head.appendChild(link)
return
}
} catch (_) {
// Storage can be unavailable in restricted browsing contexts.
}
fallback.href = fallback.dataset.defaultHref
})()
</script>
<noscript><link rel="icon" href="/huly/favicon.ico"></noscript>
</head>
<body style="margin: 0; overflow: hidden;">
</body>
</html>
</html>
+6 -1
View File
@@ -454,7 +454,12 @@ export async function configurePlatform() {
for (const link of links) {
const htmlLink = document.createElement('link')
htmlLink.rel = link.rel
htmlLink.href = link.href
if (link.rel.split(/\s+/).includes('icon') && document.getElementById('workspace-favicon') !== null) {
// Preserve the startup icon until workspace settings are available.
htmlLink.dataset.defaultHref = link.href
} else {
htmlLink.href = link.href
}
if (link.type !== undefined) {
htmlLink.type = link.type