diff --git a/src/App.test.tsx b/src/App.test.tsx
index b7abbc7..1120df5 100644
--- a/src/App.test.tsx
+++ b/src/App.test.tsx
@@ -34,8 +34,11 @@ describe("React app dashboard state view", () => {
);
expect(html).toContain('data-ui-theme-toggle="true"');
+ expect(html).toContain('data-ui-theme-current="dark"');
expect(html).toContain('aria-label="Switch to light theme"');
expect(html).not.toContain("aria-pressed");
+ expect(html).toContain("Theme");
expect(html).toContain("Dark");
+ expect(html).toContain("Light");
});
});
diff --git a/src/lib/ui/components/ThemeToggle.tsx b/src/lib/ui/components/ThemeToggle.tsx
index 1c8fb1a..d062a5b 100644
--- a/src/lib/ui/components/ThemeToggle.tsx
+++ b/src/lib/ui/components/ThemeToggle.tsx
@@ -15,15 +15,22 @@ export function ThemeToggle({ theme, onThemeChange }: ThemeToggleProps) {
);
}
diff --git a/src/lib/ui/components/render.test.tsx b/src/lib/ui/components/render.test.tsx
index 14c1ff5..1a5076d 100644
--- a/src/lib/ui/components/render.test.tsx
+++ b/src/lib/ui/components/render.test.tsx
@@ -6,6 +6,7 @@ import { FooterCell } from "./FooterCell";
import { IconButton } from "./IconButton";
import { ServiceRow } from "./ServiceRow";
import { TelemetryCard } from "./TelemetryCard";
+import { ThemeToggle } from "./ThemeToggle";
import { dashboardPreviewFixtures } from "../fixtures";
describe("dashboard UI components", () => {
@@ -144,4 +145,20 @@ describe("dashboard UI components", () => {
expect(iconButton).toContain("class=\"icon-button custom-icon-action ");
expect(iconButton).toContain("aria-expanded=\"false\"");
});
+
+ test("renders the theme toggle as a segmented instrument control", () => {
+ const body = renderToString(
+ undefined} />,
+ );
+
+ expect(body).toContain('class="theme-toggle"');
+ expect(body).toContain('data-ui-theme-current="light"');
+ expect(body).toContain('aria-label="Switch to dark theme"');
+ expect(body).toContain('class="theme-toggle__label"');
+ expect(body).toContain('class="theme-toggle__switch"');
+ expect(body).toContain('data-active="true"');
+ expect(body).toContain("Theme");
+ expect(body).toContain("Dark");
+ expect(body).toContain("Light");
+ });
});
diff --git a/src/lib/ui/components/styles.css b/src/lib/ui/components/styles.css
index 086c0c4..15125f8 100644
--- a/src/lib/ui/components/styles.css
+++ b/src/lib/ui/components/styles.css
@@ -565,35 +565,90 @@
}
.theme-toggle {
- display: inline-grid;
- grid-auto-flow: column;
- gap: var(--ui-space-2);
+ display: grid;
+ grid-template-columns: 2.72rem minmax(0, 1fr);
align-items: center;
- justify-content: center;
- min-width: 6.5rem;
- min-height: 2.15rem;
- border: var(--ui-border);
- background: var(--ui-color-surface-raised);
+ width: 9.75rem;
+ min-width: 0;
+ min-height: 2.18rem;
+ border: var(--ui-border-strong);
+ background: var(--ui-color-surface-module);
color: var(--ui-color-text);
cursor: pointer;
font: inherit;
- font-size: 0.62rem;
+ font-size: 0.55rem;
font-weight: 850;
letter-spacing: 0;
- padding: 0 var(--ui-space-3);
+ padding: 0.13rem;
text-transform: uppercase;
+ box-shadow: var(--ui-shadow-hard);
}
.theme-toggle:hover {
border-color: var(--ui-color-accent);
- color: var(--ui-color-accent);
}
-.theme-toggle span {
+.theme-toggle__label {
+ display: grid;
+ align-self: stretch;
+ place-items: center;
+ border-right: var(--ui-border);
+ color: var(--ui-color-muted);
+ font-size: 0.48rem;
+ font-weight: 800;
line-height: 1;
+}
+
+.theme-toggle__switch {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 0.1rem;
+ min-width: 0;
+ padding-left: 0.1rem;
+}
+
+.theme-toggle__cell {
+ display: grid;
+ grid-template-columns: auto auto;
+ gap: 0.2rem;
+ align-items: center;
+ justify-content: center;
+ min-height: 1.68rem;
+ border: 1px solid transparent;
+ color: var(--ui-color-muted);
+ line-height: 1;
+ padding: 0 0.22rem;
white-space: nowrap;
}
+.theme-toggle__cell[data-active="true"] {
+ border-color: var(--ui-color-accent);
+ background: var(--ui-color-accent);
+ color: var(--ui-color-accent-contrast);
+}
+
+.theme-toggle__cell > span {
+ color: currentColor;
+}
+
+.theme-toggle:hover .theme-toggle__cell[data-active="false"] {
+ border-color: var(--ui-color-line);
+ color: var(--ui-color-text);
+}
+
+.theme-toggle .icon-glyph {
+ width: 0.82rem;
+ height: 0.82rem;
+ border: 0;
+ background: transparent;
+ color: currentColor;
+}
+
+.theme-toggle .icon-glyph svg {
+ width: 0.78rem;
+ height: 0.78rem;
+}
+
.icon-glyph {
display: inline-grid;
width: 1.55rem;
diff --git a/tests/e2e/dashboard.spec.ts-snapshots/dashboard-desktop-chromium-desktop-linux.png b/tests/e2e/dashboard.spec.ts-snapshots/dashboard-desktop-chromium-desktop-linux.png
index 848033e..2c1e4f7 100644
Binary files a/tests/e2e/dashboard.spec.ts-snapshots/dashboard-desktop-chromium-desktop-linux.png and b/tests/e2e/dashboard.spec.ts-snapshots/dashboard-desktop-chromium-desktop-linux.png differ
diff --git a/tests/e2e/dashboard.spec.ts-snapshots/dashboard-light-desktop-chromium-desktop-linux.png b/tests/e2e/dashboard.spec.ts-snapshots/dashboard-light-desktop-chromium-desktop-linux.png
index 5b04c30..fc4484a 100644
Binary files a/tests/e2e/dashboard.spec.ts-snapshots/dashboard-light-desktop-chromium-desktop-linux.png and b/tests/e2e/dashboard.spec.ts-snapshots/dashboard-light-desktop-chromium-desktop-linux.png differ
diff --git a/tests/e2e/dashboard.spec.ts-snapshots/dashboard-mobile-chromium-mobile-linux.png b/tests/e2e/dashboard.spec.ts-snapshots/dashboard-mobile-chromium-mobile-linux.png
index 1f6baf4..9c8cd4e 100644
Binary files a/tests/e2e/dashboard.spec.ts-snapshots/dashboard-mobile-chromium-mobile-linux.png and b/tests/e2e/dashboard.spec.ts-snapshots/dashboard-mobile-chromium-mobile-linux.png differ