feat(a11y): label icon-only buttons
Add accessible names (and aria-pressed for toggles) to the layout switcher, overflow menu, selection clear, API key reveal/copy and pricing buttons, reusing existing i18n keys. Replace the hard-coded English 'Menu' sr-only text on the account cards with common.openMenu.
This commit is contained in:
1 parent
2e8657d7a0
commit
8e20c32117
6 files changed
+26
-3
No files matched your search
@@ -499,7 +499,7 @@ export function CloudAccountCard({
|
|||||||
className="text-muted-foreground/70 hover:text-foreground h-7 w-7"
|
className="text-muted-foreground/70 hover:text-foreground h-7 w-7"
|
||||||
>
|
>
|
||||||
<MoreVertical className="h-4 w-4" />
|
<MoreVertical className="h-4 w-4" />
|
||||||
<span className="sr-only">Menu</span>
|
<span className="sr-only">{t('common.openMenu')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end" className="w-48">
|
<DropdownMenuContent align="end" className="w-48">
|
||||||
@@ -822,7 +822,7 @@ export function CompactCloudAccountCard({
|
|||||||
className="text-muted-foreground/70 hover:text-foreground h-8 w-8"
|
className="text-muted-foreground/70 hover:text-foreground h-8 w-8"
|
||||||
>
|
>
|
||||||
<MoreVertical className="h-4 w-4" />
|
<MoreVertical className="h-4 w-4" />
|
||||||
<span className="sr-only">Menu</span>
|
<span className="sr-only">{t('common.openMenu')}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end" className="w-48">
|
<DropdownMenuContent align="end" className="w-48">
|
||||||
|
|||||||
@@ -112,6 +112,8 @@ export function AccountsToolbar(props: AccountsToolbarProps) {
|
|||||||
size="icon"
|
size="icon"
|
||||||
className="h-7 w-7 cursor-pointer rounded-md"
|
className="h-7 w-7 cursor-pointer rounded-md"
|
||||||
onClick={() => onLayoutChange('auto')}
|
onClick={() => onLayoutChange('auto')}
|
||||||
|
aria-label={t('cloud.layout.auto')}
|
||||||
|
aria-pressed={gridLayout === 'auto'}
|
||||||
>
|
>
|
||||||
<LayoutGrid className="h-3.5 w-3.5" />
|
<LayoutGrid className="h-3.5 w-3.5" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -125,6 +127,8 @@ export function AccountsToolbar(props: AccountsToolbarProps) {
|
|||||||
size="icon"
|
size="icon"
|
||||||
className="h-7 w-7 cursor-pointer rounded-md"
|
className="h-7 w-7 cursor-pointer rounded-md"
|
||||||
onClick={() => onLayoutChange('2-col')}
|
onClick={() => onLayoutChange('2-col')}
|
||||||
|
aria-label={t('cloud.layout.twoCol')}
|
||||||
|
aria-pressed={gridLayout === '2-col'}
|
||||||
>
|
>
|
||||||
<Columns2 className="h-3.5 w-3.5" />
|
<Columns2 className="h-3.5 w-3.5" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -138,6 +142,8 @@ export function AccountsToolbar(props: AccountsToolbarProps) {
|
|||||||
size="icon"
|
size="icon"
|
||||||
className="h-7 w-7 cursor-pointer rounded-md"
|
className="h-7 w-7 cursor-pointer rounded-md"
|
||||||
onClick={() => onLayoutChange('3-col')}
|
onClick={() => onLayoutChange('3-col')}
|
||||||
|
aria-label={t('cloud.layout.threeCol')}
|
||||||
|
aria-pressed={gridLayout === '3-col'}
|
||||||
>
|
>
|
||||||
<Columns3 className="h-3.5 w-3.5" />
|
<Columns3 className="h-3.5 w-3.5" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -151,6 +157,8 @@ export function AccountsToolbar(props: AccountsToolbarProps) {
|
|||||||
size="icon"
|
size="icon"
|
||||||
className="h-7 w-7 cursor-pointer rounded-md"
|
className="h-7 w-7 cursor-pointer rounded-md"
|
||||||
onClick={() => onLayoutChange('list')}
|
onClick={() => onLayoutChange('list')}
|
||||||
|
aria-label={t('cloud.layout.list')}
|
||||||
|
aria-pressed={gridLayout === 'list'}
|
||||||
>
|
>
|
||||||
<List className="h-3.5 w-3.5" />
|
<List className="h-3.5 w-3.5" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -164,6 +172,8 @@ export function AccountsToolbar(props: AccountsToolbarProps) {
|
|||||||
size="icon"
|
size="icon"
|
||||||
className="h-7 w-7 cursor-pointer rounded-md"
|
className="h-7 w-7 cursor-pointer rounded-md"
|
||||||
onClick={() => onLayoutChange('compact')}
|
onClick={() => onLayoutChange('compact')}
|
||||||
|
aria-label={t('cloud.layout.compact')}
|
||||||
|
aria-pressed={gridLayout === 'compact'}
|
||||||
>
|
>
|
||||||
<LayoutList className="h-3.5 w-3.5" />
|
<LayoutList className="h-3.5 w-3.5" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -206,7 +216,12 @@ export function AccountsToolbar(props: AccountsToolbarProps) {
|
|||||||
{/* More Options Dropdown */}
|
{/* More Options Dropdown */}
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<Button variant="outline" size="icon" className="cursor-pointer bg-white/[0.02]">
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
className="cursor-pointer bg-white/[0.02]"
|
||||||
|
aria-label={t('common.openMenu')}
|
||||||
|
>
|
||||||
<MoreHorizontal className="h-4 w-4" />
|
<MoreHorizontal className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export function BatchActionBar({
|
|||||||
size="icon"
|
size="icon"
|
||||||
className="h-6 w-6 rounded-full"
|
className="h-6 w-6 rounded-full"
|
||||||
onClick={onClearSelection}
|
onClick={onClearSelection}
|
||||||
|
aria-label={t('cloud.batch.clear')}
|
||||||
>
|
>
|
||||||
<X className="h-4 w-4" />
|
<X className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -258,6 +258,7 @@ export const ModelPricingDialog: React.FC<ModelPricingDialogProps> = ({
|
|||||||
className="text-muted-foreground hover:text-foreground h-6 w-6"
|
className="text-muted-foreground hover:text-foreground h-6 w-6"
|
||||||
onClick={() => handleReset(model)}
|
onClick={() => handleReset(model)}
|
||||||
title="Reset to default"
|
title="Reset to default"
|
||||||
|
aria-label={`Reset ${model} pricing to default`}
|
||||||
>
|
>
|
||||||
<RotateCcw className="h-3 w-3" />
|
<RotateCcw className="h-3 w-3" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -405,6 +405,8 @@ print(response.choices[0].message.content)`;
|
|||||||
className="absolute top-0 right-0 h-full px-3 py-2 hover:bg-transparent"
|
className="absolute top-0 right-0 h-full px-3 py-2 hover:bg-transparent"
|
||||||
onClick={() => setShowKey(!showKey)}
|
onClick={() => setShowKey(!showKey)}
|
||||||
title={showKey ? t('proxy.config.hide_key') : t('proxy.config.show_key')}
|
title={showKey ? t('proxy.config.hide_key') : t('proxy.config.show_key')}
|
||||||
|
aria-label={showKey ? t('proxy.config.hide_key') : t('proxy.config.show_key')}
|
||||||
|
aria-pressed={showKey}
|
||||||
>
|
>
|
||||||
{showKey ? (
|
{showKey ? (
|
||||||
<EyeOff className="text-muted-foreground h-4 w-4" />
|
<EyeOff className="text-muted-foreground h-4 w-4" />
|
||||||
@@ -537,6 +539,7 @@ print(response.choices[0].message.content)`;
|
|||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="h-7 w-7 text-blue-300 hover:bg-blue-500/10"
|
className="h-7 w-7 text-blue-300 hover:bg-blue-500/10"
|
||||||
|
aria-label={t('proxy.copy')}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
copyToClipboard(`http://${selectedIp || 'localhost'}:${proxyConfig.port}/v1`)
|
copyToClipboard(`http://${selectedIp || 'localhost'}:${proxyConfig.port}/v1`)
|
||||||
}
|
}
|
||||||
@@ -906,6 +909,7 @@ print(response.choices[0].message.content)`;
|
|||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="h-8 w-8"
|
className="h-8 w-8"
|
||||||
|
aria-label={t('proxy.copy')}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
copyToClipboard(getCurlExample(activeModelTab));
|
copyToClipboard(getCurlExample(activeModelTab));
|
||||||
@@ -938,6 +942,7 @@ print(response.choices[0].message.content)`;
|
|||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="h-8 w-8"
|
className="h-8 w-8"
|
||||||
|
aria-label={t('proxy.copy')}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
copyToClipboard(getPythonExample(activeModelTab));
|
copyToClipboard(getPythonExample(activeModelTab));
|
||||||
|
|||||||
@@ -524,6 +524,7 @@ function UsagePage() {
|
|||||||
size="icon"
|
size="icon"
|
||||||
className="ml-2 h-5 w-5 hover:bg-white/10"
|
className="ml-2 h-5 w-5 hover:bg-white/10"
|
||||||
onClick={() => setIsPricingDialogOpen(true)}
|
onClick={() => setIsPricingDialogOpen(true)}
|
||||||
|
aria-label="Model pricing settings"
|
||||||
>
|
>
|
||||||
<Settings className="text-muted-foreground h-3 w-3" />
|
<Settings className="text-muted-foreground h-3 w-3" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Reference in new issue
Block a user