diff --git a/assets/icons/logo-mark.svg b/assets/icons/logo-mark.svg
new file mode 100644
index 000000000..09e566076
--- /dev/null
+++ b/assets/icons/logo-mark.svg
@@ -0,0 +1 @@
+
diff --git a/assets/icons/logo.svg b/assets/icons/logo.svg
new file mode 100644
index 000000000..733968017
--- /dev/null
+++ b/assets/icons/logo.svg
@@ -0,0 +1 @@
+
diff --git a/rspack.config.ts b/rspack.config.ts
index cfbded0e6..f5a5ad4f2 100644
--- a/rspack.config.ts
+++ b/rspack.config.ts
@@ -93,7 +93,11 @@ const transpileModuleDirs = getTranspileModuleDirs(TRANSPILE_MODULES)
/** @type {import('@rspack/core').Configuration} */
module.exports = {
mode: isProduction ? 'production' : 'development',
- devtool: isProduction ? 'source-map' : 'eval-cheap-module-source-map',
+ // Avoid eval-based sourcemaps in development. Firefox resolves relative
+ // sourcemap URLs from injected devtools scripts like `installHook.js.map`
+ // against an `` URL when the bundle is eval-backed, which
+ // produces noisy 404s in the console.
+ devtool: isProduction ? 'source-map' : 'cheap-module-source-map',
entry: {
main: path.resolve(__dirname, 'index.web.js'),
diff --git a/src/components/icons/Logo.tsx b/src/components/icons/Logo.tsx
index 75c5cb420..09910b129 100644
--- a/src/components/icons/Logo.tsx
+++ b/src/components/icons/Logo.tsx
@@ -4,7 +4,7 @@ import {type Props, useCommonSVGProps} from './common'
import {createSinglePathSVG} from './TEMPLATE'
export const Mark = createSinglePathSVG({
- path: 'M6.335 4.212c2.293 1.76 4.76 5.327 5.665 7.241.906-1.914 3.372-5.482 5.665-7.241C19.319 2.942 22 1.96 22 5.086c0 .624-.35 5.244-.556 5.994-.713 2.608-3.315 3.273-5.629 2.87 4.045.704 5.074 3.035 2.852 5.366-4.22 4.426-6.066-1.111-6.54-2.53-.086-.26-.126-.382-.127-.278 0-.104-.041.018-.128.278-.473 1.419-2.318 6.956-6.539 2.53-2.222-2.331-1.193-4.662 2.852-5.366-2.314.403-4.916-.262-5.63-2.87C2.35 10.33 2 5.71 2 5.086c0-3.126 2.68-2.144 4.335-.874Z',
+ path: 'M374.473 57.7173C367.666 50.7995 357.119 49.1209 348.441 53.1659C347.173 53.7567 342.223 56.0864 334.796 59.8613C326.32 64.1696 314.568 70.3869 301.394 78.0596C275.444 93.1728 242.399 114.83 218.408 139.477C185.983 172.786 158.719 225.503 140.029 267.661C130.506 289.144 122.878 308.661 117.629 322.81C116.301 326.389 115.124 329.63 114.104 332.478C87.1783 336.42 64.534 341.641 47.5078 348.101C37.6493 351.84 28.3222 356.491 21.0573 362.538C13.8818 368.511 6.00003 378.262 6.00003 391.822C6.00014 403.222 11.8738 411.777 17.4566 417.235C23.0009 422.655 29.9593 426.793 36.871 430.062C50.8097 436.653 69.5275 441.988 90.8362 446.249C133.828 454.846 192.21 460 256.001 460C319.79 460 378.172 454.846 421.164 446.249C442.472 441.988 461.19 436.653 475.129 430.062C482.041 426.793 488.999 422.655 494.543 417.235C500.039 411.862 505.817 403.489 505.996 392.353L506 391.822L505.995 391.188C505.754 377.959 498.012 368.417 490.945 362.534C483.679 356.485 474.35 351.835 464.491 348.095C446.749 341.366 422.906 335.982 394.476 331.987C393.6 330.57 392.633 328.995 391.595 327.273C386.477 318.777 379.633 306.842 372.737 293.115C358.503 264.781 345.757 232.098 344.756 206.636C343.87 184.121 351.638 154.087 360.819 127.789C365.27 115.041 369.795 103.877 373.207 95.9072C374.909 91.9309 376.325 88.7712 377.302 86.6328C377.79 85.5645 378.167 84.7524 378.416 84.2224C378.54 83.9579 378.632 83.7635 378.69 83.643C378.718 83.5829 378.739 83.5411 378.75 83.5181C378.753 83.5108 378.756 83.5049 378.757 83.5015C382.909 74.8634 381.196 64.5488 374.473 57.7173Z',
})
export function Full(
@@ -14,13 +14,13 @@ export function Full(
},
) {
const {fill, size, style, gradient, ...rest} = useCommonSVGProps(props)
- const ratio = 123 / 555
+ const ratio = 123 / 641
return (
)
diff --git a/src/view/icons/Logo.tsx b/src/view/icons/Logo.tsx
index 36c956931..69b343a82 100644
--- a/src/view/icons/Logo.tsx
+++ b/src/view/icons/Logo.tsx
@@ -14,6 +14,9 @@ import {useKawaiiMode} from '#/state/preferences/kawaii'
import {flatten, useTheme} from '#/alf'
const ratio = 512 / 512
+export const LOGO_VIEW_BOX = '0 0 512 512'
+export const LOGO_PATH =
+ 'M374.473 57.7173C367.666 50.7995 357.119 49.1209 348.441 53.1659C347.173 53.7567 342.223 56.0864 334.796 59.8613C326.32 64.1696 314.568 70.3869 301.394 78.0596C275.444 93.1728 242.399 114.83 218.408 139.477C185.983 172.786 158.719 225.503 140.029 267.661C130.506 289.144 122.878 308.661 117.629 322.81C116.301 326.389 115.124 329.63 114.104 332.478C87.1783 336.42 64.534 341.641 47.5078 348.101C37.6493 351.84 28.3222 356.491 21.0573 362.538C13.8818 368.511 6.00003 378.262 6.00003 391.822C6.00014 403.222 11.8738 411.777 17.4566 417.235C23.0009 422.655 29.9593 426.793 36.871 430.062C50.8097 436.653 69.5275 441.988 90.8362 446.249C133.828 454.846 192.21 460 256.001 460C319.79 460 378.172 454.846 421.164 446.249C442.472 441.988 461.19 436.653 475.129 430.062C482.041 426.793 488.999 422.655 494.543 417.235C500.039 411.862 505.817 403.489 505.996 392.353L506 391.822L505.995 391.188C505.754 377.959 498.012 368.417 490.945 362.534C483.679 356.485 474.35 351.835 464.491 348.095C446.749 341.366 422.906 335.982 394.476 331.987C393.6 330.57 392.633 328.995 391.595 327.273C386.477 318.777 379.633 306.842 372.737 293.115C358.503 264.781 345.757 232.098 344.756 206.636C343.87 184.121 351.638 154.087 360.819 127.789C365.27 115.041 369.795 103.877 373.207 95.9072C374.909 91.9309 376.325 88.7712 377.302 86.6328C377.79 85.5645 378.167 84.7524 378.416 84.2224C378.54 83.9579 378.632 83.7635 378.69 83.643C378.718 83.5829 378.739 83.5411 378.75 83.5181C378.753 83.5108 378.756 83.5049 378.757 83.5015C382.909 74.8634 381.196 64.5488 374.473 57.7173Z'
type Props = {
fill?: PathProps['fill']
@@ -74,10 +77,7 @@ export const Logo = forwardRef(function LogoImpl(props: Props, ref) {
)}
-
+
)
})
diff --git a/src/view/icons/Logomark.tsx b/src/view/icons/Logomark.tsx
index 8d078f434..d8147e828 100644
--- a/src/view/icons/Logomark.tsx
+++ b/src/view/icons/Logomark.tsx
@@ -21,7 +21,7 @@ export function Logomark({
height={Number(size) * ratio}>
)
diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx
index 143d48332..8014e6f94 100644
--- a/src/view/shell/index.web.tsx
+++ b/src/view/shell/index.web.tsx
@@ -13,6 +13,7 @@ import {useCloseAllActiveElements} from '#/state/util'
import {Lightbox} from '#/view/com/lightbox/Lightbox'
import {ModalsContainer} from '#/view/com/modals/Modal'
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
+import {LOGO_PATH, LOGO_VIEW_BOX} from '#/view/icons/Logo'
import {Deactivated} from '#/screens/Deactivated'
import {Takendown} from '#/screens/Takendown'
import {atoms as a, select, useBreakpoints, useTheme} from '#/alf'
@@ -36,6 +37,35 @@ import {FlatNavigator, RoutesContainer} from '#/Navigation'
import {Composer} from './Composer'
import {DrawerContent} from './Drawer'
+function createFaviconDataUrl(color: string) {
+ const svg = ``
+ return `data:image/svg+xml,${encodeURIComponent(svg)}`
+}
+
+function upsertHeadLink({
+ rel,
+ href,
+ type,
+ sizes,
+}: {
+ rel: string
+ href: string
+ type?: string
+ sizes?: string
+}) {
+ let link = document.head.querySelector(`link[rel="${rel}"]`)
+
+ if (!link) {
+ link = document.createElement('link')
+ link.rel = rel
+ document.head.appendChild(link)
+ }
+
+ if (type) link.type = type
+ if (sizes) link.sizes = sizes
+ link.href = href
+}
+
function ShellInner() {
const t = useTheme()
const navigator = useNavigation()
@@ -78,6 +108,22 @@ function ShellInner() {
`
}, [t.palette.primary_500])
+ useLayoutEffect(() => {
+ const faviconHref = createFaviconDataUrl(t.palette.primary_500)
+
+ upsertHeadLink({
+ rel: 'icon',
+ href: faviconHref,
+ type: 'image/svg+xml',
+ sizes: 'any',
+ })
+ upsertHeadLink({
+ rel: 'shortcut icon',
+ href: faviconHref,
+ type: 'image/svg+xml',
+ })
+ }, [t.palette.primary_500])
+
useEffect(() => {
const unsubscribe = navigator.addListener('state', () => {
closeAllActiveElements()