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:
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 |
@@ -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 |
Reference in New Issue
Block a user