mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-21 00:11:27 -07:00
feat: optimize stats dashboard data and components
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
export type TabId = 'overview' | 'anime' | 'trends' | 'vocabulary' | 'sessions';
|
||||
import { useRef, type KeyboardEvent } from 'react';
|
||||
|
||||
export type TabId = 'overview' | 'anime' | 'trends' | 'vocabulary' | 'sessions' | 'library';
|
||||
|
||||
interface Tab {
|
||||
id: TabId;
|
||||
@@ -9,6 +11,7 @@ const TABS: Tab[] = [
|
||||
{ id: 'overview', label: 'Overview' },
|
||||
{ id: 'anime', label: 'Anime' },
|
||||
{ id: 'trends', label: 'Trends' },
|
||||
{ id: 'library', label: 'Library' },
|
||||
{ id: 'vocabulary', label: 'Vocabulary' },
|
||||
{ id: 'sessions', label: 'Sessions' },
|
||||
];
|
||||
@@ -19,18 +22,58 @@ interface TabBarProps {
|
||||
}
|
||||
|
||||
export function TabBar({ activeTab, onTabChange }: TabBarProps) {
|
||||
const tabRefs = useRef<Array<HTMLButtonElement | null>>([]);
|
||||
|
||||
const activateAtIndex = (index: number) => {
|
||||
const tab = TABS[index];
|
||||
if (!tab) return;
|
||||
tabRefs.current[index]?.focus();
|
||||
onTabChange(tab.id);
|
||||
};
|
||||
|
||||
const onTabKeyDown = (event: KeyboardEvent<HTMLButtonElement>, index: number) => {
|
||||
if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {
|
||||
event.preventDefault();
|
||||
activateAtIndex((index + 1) % TABS.length);
|
||||
return;
|
||||
}
|
||||
if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') {
|
||||
event.preventDefault();
|
||||
activateAtIndex((index - 1 + TABS.length) % TABS.length);
|
||||
return;
|
||||
}
|
||||
if (event.key === 'Home') {
|
||||
event.preventDefault();
|
||||
activateAtIndex(0);
|
||||
return;
|
||||
}
|
||||
if (event.key === 'End') {
|
||||
event.preventDefault();
|
||||
activateAtIndex(TABS.length - 1);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<nav className="flex border-b border-ctp-surface1" role="tablist" aria-label="Stats tabs">
|
||||
{TABS.map((tab) => (
|
||||
<nav
|
||||
className="flex border-b border-ctp-surface1"
|
||||
role="tablist"
|
||||
aria-label="Stats tabs"
|
||||
aria-orientation="horizontal"
|
||||
>
|
||||
{TABS.map((tab, index) => (
|
||||
<button
|
||||
key={tab.id}
|
||||
id={`tab-${tab.id}`}
|
||||
ref={(element) => {
|
||||
tabRefs.current[index] = element;
|
||||
}}
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls={`panel-${tab.id}`}
|
||||
aria-selected={activeTab === tab.id}
|
||||
tabIndex={activeTab === tab.id ? 0 : -1}
|
||||
onClick={() => onTabChange(tab.id)}
|
||||
onKeyDown={(event) => onTabKeyDown(event, index)}
|
||||
className={`px-4 py-2.5 text-sm font-medium transition-colors
|
||||
${
|
||||
activeTab === tab.id
|
||||
|
||||
Reference in New Issue
Block a user