mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-21 02:09:57 +00:00
Fix mobile nav icon accessible names
This commit is contained in:
parent
5ce4308748
commit
250bcb1f47
3 changed files with 44 additions and 3 deletions
|
|
@ -174,6 +174,10 @@ work extends shared components instead of creating new local variants.
|
|||
durable plan-capacity explanation, over-plan reasoning, and upgrade/review
|
||||
actions belong in the `cloud-paid` plan surface rather than permanent
|
||||
banner-local prose.
|
||||
Mobile navigation under the same shared boundary owns tab accessible names:
|
||||
icon components may keep their standalone labels, but the nav must treat
|
||||
those icons as decorative inside tab buttons so names come from the tab
|
||||
label plus meaningful badge counts, not duplicated icon titles.
|
||||
2. Route new top-level settings surfaces through the canonical settings shell
|
||||
instead of introducing page-local framing.
|
||||
Shared shells and primitives that need websocket or dark-mode context must
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export function MobileNavBar(props: MobileNavBarProps) {
|
|||
enabled: platform.enabled,
|
||||
})}
|
||||
>
|
||||
<span class="relative flex items-center justify-center">
|
||||
<span aria-hidden="true" class="relative flex items-center justify-center">
|
||||
<Icon class={tabIconClass} />
|
||||
</span>
|
||||
<span class="whitespace-nowrap">{platform.label}</span>
|
||||
|
|
@ -72,7 +72,9 @@ export function MobileNavBar(props: MobileNavBarProps) {
|
|||
})}
|
||||
>
|
||||
<span class="relative flex items-center justify-center">
|
||||
<Icon class={tabIconClass} />
|
||||
<span aria-hidden="true" class="inline-flex items-center justify-center">
|
||||
<Icon class={tabIconClass} />
|
||||
</span>
|
||||
<Show when={alertBadges()}>
|
||||
{(badges) => (
|
||||
<span class="absolute -right-2 -top-1 flex items-center gap-1">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { fireEvent, render, screen, waitFor } from '@solidjs/testing-library';
|
||||
import { fireEvent, render, screen, waitFor, within } from '@solidjs/testing-library';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { Component } from 'solid-js';
|
||||
import mobileNavBarSource from '@/components/shared/MobileNavBar.tsx?raw';
|
||||
|
|
@ -16,6 +16,12 @@ const DashboardIcon: Component<{ class?: string }> = (props) => <span class={pro
|
|||
const StorageIcon: Component<{ class?: string }> = (props) => <span class={props.class}>ST</span>;
|
||||
const AlertsIcon: Component<{ class?: string }> = (props) => <span class={props.class}>AL</span>;
|
||||
const SettingsIcon: Component<{ class?: string }> = (props) => <span class={props.class}>SE</span>;
|
||||
const PatrolIcon: Component<{ class?: string }> = (props) => (
|
||||
<svg aria-label="Pulse Patrol" class={props.class} viewBox="0 0 24 24">
|
||||
<title>Pulse Patrol</title>
|
||||
<circle cx="12" cy="12" r="8" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
describe('MobileNavBar', () => {
|
||||
it('keeps the mobile nav on shell, runtime, and model owners', () => {
|
||||
|
|
@ -37,6 +43,35 @@ describe('MobileNavBar', () => {
|
|||
expect(mobileNavBarModelSource).toContain('getMobileNavFadeState');
|
||||
});
|
||||
|
||||
it('keeps decorative icon labels out of mobile tab accessible names', () => {
|
||||
render(() => (
|
||||
<MobileNavBar
|
||||
activeTab={() => 'ai'}
|
||||
platformTabs={() => []}
|
||||
utilityTabs={() => [
|
||||
{
|
||||
id: 'ai',
|
||||
label: 'Patrol',
|
||||
route: '/patrol',
|
||||
tooltip: 'Continuous verification',
|
||||
badge: null,
|
||||
count: undefined,
|
||||
breakdown: undefined,
|
||||
icon: PatrolIcon,
|
||||
},
|
||||
]}
|
||||
onPlatformClick={() => {}}
|
||||
onUtilityClick={() => {}}
|
||||
/>
|
||||
));
|
||||
|
||||
const navList = screen.getByRole('tablist', { name: 'Mobile navigation' });
|
||||
const patrolButton = within(navList).getByRole('button', { name: 'Patrol' });
|
||||
|
||||
expect(patrolButton).toHaveAttribute('data-tab-id', 'ai');
|
||||
expect(within(navList).queryByRole('button', { name: 'Pulse Patrol Patrol' })).toBeNull();
|
||||
});
|
||||
|
||||
it('orders tabs, renders alert badges, and shows fades from scroll state', async () => {
|
||||
const onPlatformClick = vi.fn();
|
||||
const onUtilityClick = vi.fn();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue