feat(FN-2266): align PWA and favicon assets with dashboard brand mark

- Replace public logo.svg with the header ring+swoosh geometry to keep branding consistent
- Refresh icon-192.png and icon-512.png assets to match the updated dashboard mark
- Add PWA tests that validate logo.svg structure and ensure install icon files exist
- Document favicon/PWA brand alignment expectations in the dashboard README
This commit is contained in:
Fusion
2026-04-22 15:14:47 -07:00
committed by gsxdsm
parent 8bd0538a72
commit 2455bfb250
6 changed files with 54 additions and 5 deletions

View File

@@ -523,6 +523,8 @@ All color themes automatically provide values for these tokens. Adding a new col
**Header brand lockup:** The logo SVG and "Fusion" wordmark are wrapped in a dedicated `.header-brand` flex container with `gap: var(--space-xs)` (4 px). This isolates logo-to-wordmark spacing from the wider `.header-left` gap (`var(--space-sm)`, 8 px) so the brand mark can be tuned independently of the spacing between the brand group and adjacent header controls (project selector, back button, etc.).
**Favicon and PWA icon alignment:** The public favicon (`app/public/logo.svg`) and PWA install icons (`app/public/icons/icon-192.png`, `app/public/icons/icon-512.png`) intentionally mirror the header logo geometry — the outer ring and swoosh/comet shape from `Header.tsx`. This ensures users see one consistent brand mark across the dashboard UI, browser tab favicon, and installed PWA shortcuts. The logo assets use `currentColor` for theme-driven coloring, matching the header's approach.
## Performance Characteristics
The dashboard includes several runtime safeguards to stay responsive during long sessions and on larger boards:

View File

@@ -66,4 +66,51 @@ describe("PWA configuration", () => {
expect(swSource).toContain('addEventListener("activate"');
expect(swSource).toMatch(/fusion-cache-v\d+/);
});
describe("logo assets", () => {
it("logo.svg uses ring + swoosh geometry matching Header.tsx brand mark", () => {
const logoSvg = readFileSync(resolve(__dirname, "../public/logo.svg"), "utf8");
// Must contain the outer ring (circle with r=52, matching Header.tsx header-logo)
expect(logoSvg).toContain('cx="64"');
expect(logoSvg).toContain('cy="64"');
expect(logoSvg).toContain('r="52"');
expect(logoSvg).toContain('stroke-width="8"');
// Must contain the swoosh/comet path shape (d attribute from Header.tsx)
// The path starts with M26 101C... and creates the comet-like swoosh
expect(logoSvg).toContain('d="M26 101');
expect(logoSvg).toContain("fill=\"currentColor\"");
// Must use SVG namespace
expect(logoSvg).toContain("xmlns=");
});
it("logo.svg does not contain retired 4-circle glyph pattern", () => {
const logoSvg = readFileSync(resolve(__dirname, "../public/logo.svg"), "utf8");
// The old 4-circle glyph used circles at (44,44), (84,44), (44,84), (84,84) with r=20
// Verify these specific circle positions are NOT present
expect(logoSvg).not.toContain("cx=\"44\"");
expect(logoSvg).not.toContain("cy=\"44\"");
expect(logoSvg).not.toContain("r=\"20\"");
});
it("PWA icon files exist with correct sizes", async () => {
const fs = await import("node:fs");
const icon192Path = resolve(__dirname, "../public/icons/icon-192.png");
const icon512Path = resolve(__dirname, "../public/icons/icon-512.png");
expect(fs.existsSync(icon192Path)).toBe(true);
expect(fs.existsSync(icon512Path)).toBe(true);
// Verify PNG files have reasonable size (not empty)
const stats192 = fs.statSync(icon192Path);
const stats512 = fs.statSync(icon512Path);
expect(stats192.size).toBeGreaterThan(100);
expect(stats512.size).toBeGreaterThan(100);
});
});
});

View File

@@ -1,6 +1,6 @@
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { AlertTriangle, ExternalLink, Eye, Loader2, Monitor, Play, RefreshCw, RotateCw, ShieldAlert, Square } from "lucide-react";
import type { DetectedDevServerCommand } from "../api";
import type { DetectedDevServerCommand, DevServerSession, DevServerState } from "../api";
import { useDevServer } from "../hooks/useDevServer";
import { useDevServerConfig } from "../hooks/useDevServerConfig";
import { useDevServerLogs } from "../hooks/useDevServerLogs";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1,6 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" fill="none">
<circle cx="44" cy="44" r="20" fill="currentColor"/>
<circle cx="84" cy="44" r="20" fill="currentColor"/>
<circle cx="44" cy="84" r="20" fill="currentColor"/>
<circle cx="84" cy="84" r="20" fill="currentColor"/>
<!-- Outer ring: matches Header.tsx header-logo geometry -->
<circle cx="64" cy="64" r="52" stroke="currentColor" stroke-width="8" fill="none"/>
<!-- Swoosh/comet shape: matches Header.tsx header-logo path -->
<path d="M26 101C44 82 62 64 82 45C90 37 98 30 104 24C96 35 89 47 81 60C70 79 57 95 43 108C38 112 32 108 26 101Z" fill="currentColor"/>
</svg>

Before

Width:  |  Height:  |  Size: 302 B

After

Width:  |  Height:  |  Size: 436 B